Save a list to a file - python

I have a library where I want to create a new book and then add it to my list of books.
What I have problems with is to save the file between calls.
This is how I read the file:
def read_bookfile():
try:
booklibrary_file = open("a.txt")
booklibrary_list = []
booklist = booklibrary_file.readlines()
for rad in booklist:
linelist = rad.split("/")
title = linelist[0]
firstname = linelist[1]
lastname = linelist[2]
isbn = int(linelist[3])
availability = linelist[4]
borrowed = linelist[5]
late = linelist[6]
returnday = linelist[7]
b = Book(title, firstname, lastname, isbn, availability, borrowed, late, returnday)
booklibrary_list.append(b)
booklibrary_file.close()
return booklibrary_list
Now I want to know how to save to my file.

In order to save to a file, you have to open it in Write-Append mode.
library_file = open("a.txt", "a")
...
library_file.write("Some string\n")
...
library_file.close()
Refer to Python's documentation on Built-in Functions for more information.

First off, here's an easier way to read, assuming those eight fields are the only ones:
def read_bookfile(filename="a.txt"):
with open(filename) as f:
return [Book(*line.split('/')) for line in f]
Now, to save:
def save_bookfile(booklist, filename='a.txt'):
with open(filename, 'w') as f:
for book in booklist:
f.write('/'.join([book.title, book.firstname, book.lastname, str(book.isbn),
book.availability, book.borrowed, book.late, book.returnday])
+ '\n')
assuming the Book model just saves those attributes in as they were passed (as strings).
Explanations:
The with statement opens your file and makes sure that it gets closed when control passes out of the statement, even if there's an exception or something like that.
Passing in the filename as an argument is preferable, because it allows you to use different filenames without changing the function; this uses a default argument so you can still call it in the same way.
The [... for line in f] is a list comprehension, which is like doing lst = []; for line in f: lst.append(...) but faster to write and to run.
Opening a file in 'w' mode allows you to write to it. Note that this will delete the already-existing contents of the file; you can use 'a' or 'w+' to avoid that, but that requires a little more work to reconcile the existing contents with your book list.
The * in read_bookfile splits a list up as if you passed them as separate arguments to a function.
'/'.join() takes the list of strings and joins them together using slashes: '/'.join(["a", "b", "c"]) is "a/b/c". It needs strings, though, which is why I did str(isbn) (because book.isbn is an int).

Python is "batteries included", remember?
Consider using the "csv" module:
use csv
csv.reader(...)
csv.writer(...)
I think these have lots of options (like you can set your delimiters to be other than commas; you can read in to a list of dictionaries, etc.)
See Python Docs for CSV reader/writer:

I have to make a few assumptions about your Book class, but I think this might help put you on the right track:
bookList = read_bookfile()
outfile = open("booklist.txt", "w")
for book in bookList:
bookStr = book.title + " " + book.firstname + " " + book.lastname + " " + book.isbn + " " + book.availability + " " + book.borrowed + " " + book.late + " " + book.returnday + "\n"
outfile.write(bookStr)
outfile.close()

Related

How to write a method to delete some lines in a file with a flask request?

I must write a method to delete some lines in a txt file. The lines are defined by the request in the flask route. I don't find how to do....
For now, it deletes everything in the file.
I wrote that:
class Book:
#properties
def __init__(self, title, author, genre, comment, ):
self.title = title
self.author = author
self.genre = genre
self.comment = comment
self.identity = id(self)
##methods
#write info book in db.txt
def write_info_book(self, file):
file = open("booksdb.txt", "a")
file.write("Title: " +self.title +"\n")
file.write("\t" + "Author: " + self.author + "\n")
file.write("\t"+ "Genre: " + self.genre + "\n")
file.write("\t"+ "Your comment: " + self.comment + "\n")
file.write("---" + "\n")
file.close()
#delete a book in txt file
def delete_book_txt(self, file):
file = open("booksdb.txt", "r")
content = file.read()
file.close()
file = open("booksdb.txt", "w")
books = content.split("---")
books = get_books_to_delete()
title = flask.request.args.get("b")
for book in books:
if book.lower().find(title.lower()) != -1:
file.write(books)
And the route:
#app.route("/delete")
def delete():
title = flask.request.args.get("b")
html_page =get_html("delete")
Book.delete_book_txt( file= "booksdb.txt")
if title == None or title == "":
return html_page.replace("$$DELETE$$", "You didn't enter any book to delete")
else:
return html_page.replace("$$DELETE$$", title)
I really don't understand how i should do.... I really hope someone can help me, because whatever I try, it doesn't work
You're not thinking about what you have. content is the entire file. books is a list of individual books, but then you immediately throw that away, and replace it with your list of books to delete.
And why do you pass the file name as a parameter (called "file"), and then immediately reuse that name by opening a hardcoded file name? You're not thinking about what data you have and what data you need.
There are two ways to delete lines from a file. (1) open both files, for each line in the old file, if you want to keep the line write it, else don't write it. (2) Open first file, read lines into a list, manipulate the list (adding, replacing), join the lines using your separator, write the joined list to file.
So:
def delete_book_txt(self, file):
books = open(file, "r").split('---')
newbooks = []
title = flask.request.args.get("b")
for book in books:
if title.lower() not in book.lower():
newbooks.append(book)
open(file,"w").write('---'.join(newbooks))
In the long term, of course, the right answer is to use a database. SQLite is built-in to Python, and would be a perfectly good way to store your books.

Save output from biopython object into a file?

Here i have a code written to extract "locus_tag" of gene using "id". How can i save the output from this into a file in a tab seperated format????code adopted and modified https://www.biostars.org/p/110284/
from Bio import SeqIO
foo = open("geneid.txt")
lines = foo.read().splitlines()
genbank_file = open("example.gbk")
for record in SeqIO.parse(genbank_file, "genbank"):
for f in record.features:
if f.type == "CDS" and "protein_id" in f.qualifiers:
protein_id = f.qualifiers["protein_id"][0]
if protein_id in lines:
print f.qualifiers["protein_id"][0],f.qualifiers["locus_tag"][0]
Try adding something like this -- but you will need to make certain the indentations are correct with the code that you have already written.
with open(your_outputFileName, 'w') as outputFile:
string = '\t'.join([f.qualifiers['protein_id'][0],f.qualifiers['locus_tag'][0]])
outputFile.write(string + '\n')
You should also consider opening your initial file using "with". This will automatically close the file when you are done with it -- otherwise -- be certain to close the file (e.g., foo.close()).
for record in SeqIO.parse(genbank_file, 'genbank'):
for f in record.features:
if f.type == 'CDS' and 'protein_id' in f.qualifiers:
protein_id = f.qualifiers['protein_id'][0]
if protein_id in lines:
print f.qualifiers['protein_id'][0],f.qualifiers['locus_tag'][0]
with open('your_outputFileName', 'w') as outputFile:
string = '\t'.join([f.qualifiers['protein_id'][0],f.qualifiers['locus_tag'][0]]) + '\n'
outputFile.write(string)

I/O Error with open()

class NewTab():
def __init__(self, song_title, artist_name):
self.song_title = song_title
self.artist_name = artist_name
name1 = self.artist_name + "_" + self.song_title
name2 = name1.replace(" ", "")
new_file = open("~/Documents/"+name2+".txt", "a+")
tab = NewTab(raw_input("Song Title: "), raw_input("Artist Name: "))
I am trying to create a new file (assuming it doesn't already exist) whose name is generated from two strings of User input. For example:
"Song Title: " >> Personal Jesus
"Artist Name: " >> Depeche Mode
should result in creating: ~/Documents/DepecheMode_PersonalJesus.txt
Unfortunately I am always left with:
IOError: [Errno 2] No such file or director: '~/Documents/DepecheMode_PersonalJesus.txt'
I have tried different open() modes, such as "w", "w+" and "r+" to no avail.
I have also tried placing name1, name2, and new_file into a method outside of __init__ like so:
def create_new(self):
name1 = self.artist_name + "_" + self.song_title
name2 = name1.replace(" ", "")
new_file = open("~/Documents/"+name2+".txt", "a+")
tab.create_new()
but this results in the exact same Error.
I have set my /Documents folder Permissions (Owner, Group, Others) to Create and delete files.
Beyond that, I am at a complete loss as to why I cannot create this file. It is clearly structuring the file name and directory the way that I want it, so why won't it go ahead and create the file?
Use os.path.expanduser() function to get a full valid path with "~" resolved and pass this to open()
new_file = open(os.path.expanduser("~/Documents/")+name2+".txt", "a+")
this will resolve "~" to something like /home/user and join it with the rest of the path elements.
If you don't necessarily need to use "a+" then having "wb" as a second parameter will automatically open a file.
foo = open("bar", "wb")

How should I replace parts from a text file through Python?

Okay, so here's the deal, folks:
I've been experimenting with Python(3.3), trying to create a python program capable of generating random names for weapons in a game and replacing their old names, which are located inside a text file. Here's my function:
def ModifyFile(shareddottxt):
global name
a = open(str(shareddottxt) , 'r')
b = a.read()
namefix1 = '''SWEP.PrintName = "'''
namefix2 = '''" //sgaardname'''
name1 = b.find(namefix1) + len(namefix1)
name2 = b.find(namefix2, name1)
name = name + b[name1:name2] ## We got our weapon's name! Let's add the suffix.
c = open((shareddottxt + ".lua"), 'r+')
for line in b:
c.write(line.replace(name, (name + namesuffix)))
c.close()
a.close
As you can see, I first open my text file to find the weapon's name. After that, I try to create a new file and copy the contents from the old one, while replacing the weapon's name for (name + namesuffix). However, after calling the function, I get nothing. No file whatsoever. And even if I DO add the file to the folder manually, it does not change. At all.
Namesuffix is generated through another function early on. It is saved as a global var.
Also, my text file is huge, but the bit I'm trying to edit is:
SWEP.PrintName = "KI Stinger 9mm" //sgaardname
The expected result:
SWEP.PrintName = "KI Stinger 9mm NAMESUFFIX" //sgaardname
Where did I mess up, guys?
Something like this is more pythonic.
def replace_in_file(filename, oldtext, newtext):
with open(filename, 'r+') as file:
lines = file.read()
new_lines = lines.replace(oldtext, newtext)
file.seek(0)
file.write(new_lines)
If you don't want to replace that file
def replace_in_file(filename, oldtext, newtext):
with open(filename, 'r') as file, open(filename + ".temp", 'w') as temp:
lines = file.read()
new_lines = lines.replace(oldtext, newtext)
temp.write(new_lines)

Naming multiple files in python and scrapy

I'm trying to save files to a directory after scraping them from the web using scrapy. I'm extracting a date from the file and using that as the file name. The problem I'm running into, however, is that some files have the same date, i.e. there are two files that would take the name "June 2, 2009". So, what I'm looking to do is somehow check whether there is already a file with the same name, and if so, name it something like "June 2, 2009.1" or some such.
The code I'm using is as follows:
def parse_item(self, response):
self.log('Hi, this is an item page! %s' % response.url)
response = response.replace(body=response.body.replace('<br />', '\n'))
hxs = HtmlXPathSelector(response)
date = hxs.select("//div[#id='content']").extract()[0]
dateStrip = re.search(r"([A-Z]*|[A-z][a-z]+)\s\d*\d,\s[0-9]+", date)
newDate = dateStrip.group()
content = hxs.select("//div[#id='content']")
content = content.select('string()').extract()[0]
filename = ("/path/to/a/folder/ %s.txt") % (newDate)
with codecs.open(filename, 'w', encoding='utf-8') as output:
output.write(content)
You can use os.listdir to get a list of existing files and allocate a filename that will not cause conflict.
import os
def get_file_store_name(path, fname):
count = 0
for f in os.listdir(path):
if fname in f:
count += 1
return os.path.join(path, fname+str(count))
# This is example to use
print get_file_store_name(".", "README")+".txt"
The usual way to check for existence of a file in the C library is with a function called stat(). Python offers a thin wrapper around this function in the form of os.stat(). I suggest you use that.
http://docs.python.org/library/stat.html
def file_exists(fname):
try:
stat_info = os.stat(fname)
if os.S_ISREG(stat_info): # true for regular file
return True
except Exception:
pass
return False
one other solution is you can append time with date, for naming file like
from datetime import datetime
filename = ("/path/to/a/folder/ %s_%s.txt") % (newDate,datetime.now().strftime("%H%M%S"))
The other answer pointed me in the correct direction by checking into the os tools in python, but I think the way I found is perhaps more straightforward. Reference here How do I check whether a file exists using Python? for more.
The following is the code I came up with:
existence = os.path.isfile(filename)
if existence == False:
with codecs.open(filename, 'w', encoding='utf-8') as output:
output.write(content)
else:
newFilename = ("/path/.../.../- " + '%s' ".1.txt") % (newDate)
with codecs.open(newFilename, 'w', encoding='utf-8') as output:
output.write(content)
Edited to Add:
I didn't like this solution too much, and thought the other answer's solution was probably better but didn't quite work. The main part I didn't like about my solution was that it only worked with 2 files of the same name; if three or four files had the same name the initial problem would occur. The following is what I came up with:
filename = ("/Users/path/" + " " + "title " + '%s' + " " + "-1.txt") % (date)
filename = str(filename)
while True:
os.path.isfile(filename)
newName = filename.replace(".txt", "", filename)
newName = str.split(newName)
newName[-1] = str(int(newName[-1]) + 1)
filename = " ".join(newName) + ".txt"
if os.path.isfile(filename) == False:
with codecs.open(filename, 'w', encoding='utf-8') as output:
output.write(texts)
break
It probably isn't the most elegant and might be kind of a hackish approach, but it has worked so far and seems to have addressed my problem.

Categories