How to Change First Line of File in Python? - python

Why does Python-2.7 on Windows truncate a file? The problem is well known with shutil.copyfile but I don't understand how to avoid it when I'm changing the first line. File size is unknown and could be huge.
Reference below but I'd prefer better exception handling with something like the following code:
import os
import sys
import shutil
with open(sys.argv[1], 'r+') as src:
line = src.readline()
with open(sys.argv[1], 'r+') as dst:
dst.write = sys.argv[1]+'\n'
shutil.copyfileobj(src, dst)
Reference: change first line of a file in python

You need to create the new version of the file as a NamedTemporaryFile. After you finish constructing it, you then rename it on top of the old file.
Code:
def insert_line_front(insert_filename, to_insert):
with open(insert_filename) as src, tempfile.NamedTemporaryFile(
'w', dir=os.path.dirname(insert_filename), delete=False) as dst:
# Discard first line
src.readline()
# Save the new first line
dst.write(to_insert + '\n')
# Copy the rest of the file
shutil.copyfileobj(src, dst)
# remove old version
os.unlink(insert_filename)
# rename new version
os.rename(dst.name, insert_filename)
return()
Test Code:
import os
import shutil
import sys
import tempfile
# For noob - Function code goes here
filename = os.path.abspath(sys.argv[1])
insert_line_front(filename, filename)
Before:
/testcode/file1
"-3.588920831680E-02","1.601887196302E-01","1.302309112549E+02"
"3.739478886127E-01","1.782759875059E-01","6.490543365479E+01"
"3.298096954823E-01","6.939357519150E-02","2.112392578125E+02"
"-2.319437451661E-02","1.149862855673E-01","2.712340698242E+0
After:
/testcode/file2
"-3.588920831680E-02","1.601887196302E-01","1.302309112549E+02"
"3.739478886127E-01","1.782759875059E-01","6.490543365479E+01"
"3.298096954823E-01","6.939357519150E-02","2.112392578125E+02"
"-2.319437451661E-02","1.149862855673E-01","2.712340698242E+0

Related

Delete a temporal file when it is closed in Python

I have a function similar to this:
def open_tmp():
tmp = mktemp()
copy('file.txt', tmp)
return open(tmp, 'rt')
And I would like to remove automatically the created temporal file when the file will close, for example:
file = open_tmp()
# Do something with file
file.close() # I want to remove the temporal file here
Is it possible? I thought to create a subclass of BaseIO and rewrite the close() function, but I think it is too much work because I would have to rewrite all the BaseIO methods.
You can try this code snippet. As per security concern I recommended to use tempfile instead of your code.
import os
import tempfile
new_file, file_path = tempfile.mkstemp()
try:
with os.fdopen(new_file, 'w') as temp_file:
# Do something with file
temp_file.write('write some dumy text in file')
finally:
os.remove(file_path)
I've found the solution:
import os
import tempfile
def open_tmp():
tmp = tempfile.mkstemp()
copy('file.txt', tmp) # This copy the file.txt to tmp
file = open(tmp, 'rt')
old_close = file.close
def close():
old_close()
os.remove(tmp)
file.close = close
return file

Avoid date changes in Zipfile.write

Looking at Zipfile module, I'm trying to figure out why the content of zipfile changes when I recreate a file with the same content
Here's a sample code I'm working on:
import os
import hashlib
import zipfile
from io import BytesIO
FILE_PATH = './'
SAMPLE_FILE = "zip_test123.txt"
# create an empty file
new_file = FILE_PATH+"/"+SAMPLE_FILE
try:
open(new_file, 'x')
except FileExistsError:
os.remove(new_file)
open(new_file, 'x')
full_path = os.path.expanduser(FILE_PATH)
# zip it
data = BytesIO()
with zipfile.ZipFile(data, mode='w') as zf:
zf.write(os.path.join(full_path, SAMPLE_FILE), SAMPLE_FILE)
zip_cntn = data.getvalue()
data.close()
print(zip_cntn)
print(hashlib.md5(zip_cntn).hexdigest())
This first creates an empty file, then zip it and prints out the hash of zipped data.
Running this multiple times results in differnt contents/hash, which I think is caused by modification date (my assumption is based on this which shows the Modified date as well)
I'm only interested in zipping the actual contents, and not anything else (e.g. hash should stay the same if I recreate the same content for a given file)
Any suggestion how to achieve this goal/ignore extra info while archiving a file?

Not able to fix file handling issue in python

I wrote python code to search a pattern in a tcl file and replace it with a string, it prints the output but the same is not saved in the tcl file
import re
import fileinput
filename=open("Fdrc.tcl","r+")
for i in filename:
if i.find("set qa_label")!=-1:
print(i)
a=re.sub(r'REL.*','harsh',i)
print(a)
filename.close()
actual result
set qa_label
REL_ts07n0g42p22sadsl01msaA04_2018-09-11-11-01
set qa_label harsh
Expected result is that in my file it should reflect the same result as above but it is not
You need to actually write your changes back to disk if you want to see them affected there. As #ImperishableNight says, you don't want to do this by trying to write to a file you're also reading from...you want to write to a new file. Here's an expanded version of your code that does that:
import re
import fileinput
fin=open("/tmp/Fdrc.tcl")
fout=open("/tmp/FdrcNew.tcl", "w")
for i in fin:
if i.find("set qa_label")!=-1:
print(i)
a=re.sub(r'REL.*','harsh',i)
print(a)
fout.write(a)
else:
fout.write(i)
fin.close()
fout.close()
Input and output file contents:
> cat /tmp/Fdrc.tcl
set qa_label REL_ts07n0g42p22sadsl01msaA04_2018-09-11-11-01
> cat /tmp/FdrcNew.tcl
set qa_label harsh
If you wanted to overwrite the original file, then you would want to read the entire file into memory and close the input file stream, then open the file again for writing, and write modified content to the same file.
Here's a cleaner version of your code that does this...produces an in memory result and then writes that out using a new file handle. I am still writing to a different file here because that's usually what you want to do at least while you're testing your code. You can simply change the name of the second file to match the first and this code will overwrite the original file with the modified content:
import re
lines = []
with open("/tmp/Fdrc.tcl") as fin:
for i in fin:
if i.find("set qa_label")!=-1:
print(i)
i=re.sub(r'REL.*','harsh',i)
print(i)
lines.append(i)
with open("/tmp/FdrcNew.tcl", "w") as fout:
fout.writelines(lines)
Open a tempfile for writing the updated file contents and open the file for writing.
After modifying the lines, write it back in the file.
import re
import fileinput
from tempfile import TemporaryFile
with TemporaryFile() as t:
with open("Fdrc.tcl", "r") as file_reader:
for line in file_reader:
if line.find("set qa_label") != -1:
t.write(
str.encode(
re.sub(r'REL.*', 'harsh', str(line))
)
)
else:
t.write(str.encode(line))
t.seek(0)
with open("Fdrc.tcl", "wb") as file_writer:
file_writer.writelines(t)

changing the value in ASCII file and saving it as with different name - Python

I have one ASCII file with .dat extention. The file has a data as shown below,
MPOL3_VPROFILE
{
ID="mpvp_1" Cycle="(720)[deg]" Lift="(9)[mm]" Period="(240)[deg]"
Phase="(0)[deg]" TimingHeight="(1.0)[mm]" RampTypeO="Const Velo"
RampHO="(0.3)[mm]" RampVO="(0.00625)[mm/deg]" RampTypeC="auto"
RampHC="(auto)[mm]" RampVC="(auto)[mm/deg]" bO="0.7" cO="0.6" dO="1.0"
eO="1.5" bC="auto" cC="auto" dC="auto" eC="auto" th1O="(14)[deg]"
Now I would like to read this file in Python and then change the value of RampHO="(0.3)[mm]" to lets say RampHO="(0.2)[mm]" and save it as a new .dat file. How can I do this ?
Currently I am able to read the file and line successfully using below code,
import sys
import re
import shutil
import os
import glob
import argparse
import copy
import fileinput
rampOpen = 'RampHO='
file = open('flatFollower_GenCam.dat','r')
#data = file.readlines()
#print (data)
for line in file:
line.strip().split('/n')
if rampOpen in line:
print (line[4:22])
But I am now stuck how to change the float value and save it as with different name.
First up, you should post your code inside your text and not in seperate images. Just indent each line with four spaces to format it as code.
You can simply read in a file line by line, change the lines you want to change and then write the output.
with open(infile, 'r') as f_in, open(outfile, 'w') as f_out:
for line in f_in:
output_line = edit_line(line)
f_out.write(output_line)
Then you just have to write a function that does the string replacement.

Empty/blank result file when using shutil to copy a tempfile

import tempfile
import shutil
tmp_f = tempfile.NamedTemporaryFile(delete=False)
tmp_f.write("hello world")
shutil.copy(tmp_f.name, "/etc/exports")
When I read /etc/exports, it is a completely empty file. what is wrong?
You need to close the file:
tmp_f.write("hello world")
tmp_f.close()
In addition to closing the file, it You can use .flush() to write the buffer to disk. This may be beneficial in cases when you want to move the file after writing to it, but also want to take advantage of a context manager and delete=True (the default mode) to automatically clean up the temp file. For example:
import os
import shutil
import tempfile
destination_path = "hello.txt"
content = "hello world"
with tempfile.NamedTemporaryFile() as temp:
temp.write(content.encode("utf-8"))
temp.flush()
shutil.copy(temp.name, destination_path)
with open(destination_path) as f:
print(f.read())
os.remove(destination_path)

Categories