python - txt - ¿Cómo se abre(lectura-escritura) o se crea un archivo con truncamiento permitido?
lectura y escritura de archivos en java (4)
Bueno, solo existen estos modos, y todos ellos tienen los "defectos" que enumeró.
Su única opción es open()
. ¿Por qué no algo como esto? (Pitón)
def touchopen(filename, *args, **kwargs):
open(filename, "a").close() # "touch" file
return open(filename, *args, **kwargs)
se comporta como abierto, incluso podría volver a vincularlo para abrir () si realmente lo desea.
todas las características de open se conservan, incluso puedes hacer:
with touchopen("testfile", "r+") as testfile:
do_stuff()
Por supuesto, puede crear un gestor de contexto que abra el archivo en modo +, lo lea en la memoria e intercepte las escrituras para manejar el truncado creando mágicamente un archivo temporal en modo w, y cambie el nombre de ese archivo temporal al archivo original cuando lo cierre, pero eso sería excesivo, supongo.
Quiero:
- abra un archivo en modo lectura-escritura, si existe;
- crearlo si no existe;
- ser capaz de truncarlo en cualquier momento y en cualquier lugar.
EDITAR : con truncado quiero decir escribir hasta una posición y descartar la parte restante del archivo, si está presente
Todo esto atómicamente (con una sola llamada a open()
o simulando una sola llamada a open()
)
No se aplica ninguna modalidad abierta única:
- r: obviamente no funciona;
- r +: falla si el archivo no existe;
- w: recrear el archivo si existe;
- w +: recrear el archivo si existe;
- a: no puede leer;
- a +: no se puede truncar
Algunas combinaciones que probé (rw, rw +, r + w, etc.) tampoco parecen funcionar. ¿Es posible?
Algunos doc de Ruby (se aplica a python también):
r
Read-only mode. The file pointer is placed at the beginning of the file.
This is the default mode.
r+
Read-write mode. The file pointer will be at the beginning of the file.
w
Write-only mode. Overwrites the file if the file exists. If the file
does not exist, creates a new file for writing.
w+
Read-write mode. Overwrites the existing file if the file exists. If the
file does not exist, creates a new file for reading and writing.
a
Write-only mode. The file pointer is at the end of the file if the file
exists. That is, the file is in the append mode. If the file does not exist,
it creates a new file for writing.
a+
Read and write mode. The file pointer is at the end of the file if the file
exists. The file opens in the append mode. If the file does not exist, it
creates a new file for reading and writing.
De acuerdo con OpenGroup :
O_TRUNC
Si el archivo existe y es un archivo normal, y el archivo se abre correctamente O_RDWR u O_WRONLY, su longitud se trunca a 0 y el modo y el propietario permanecen sin cambios. No tendrá ningún efecto en los archivos especiales FIFO o en los archivos del dispositivo terminal. Su efecto en otros tipos de archivos depende de la implementación. El resultado de usar O_TRUNC con O_RDONLY no está definido.
Entonces, O_TRUNC probablemente se pasa al abrir un archivo con "w" o "w +". Esto le da a "truncamiento" un significado diferente, no lo que yo quiero.
Con python, la solución parece abrir el archivo en la E / S de bajo nivel con la función os.open()
.
La siguiente función de python:
def touchopen(filename, *args, **kwargs):
# Open the file in R/W and create if it doesn''t exist. *Don''t* pass O_TRUNC
fd = os.open(filename, os.O_RDWR | os.O_CREAT)
# Encapsulate the low-level file descriptor in a python file object
return os.fdopen(fd, *args, **kwargs)
tiene el comportamiento que quería. Puedes usarlo así (de hecho es mi caso de uso):
# Open an existing file or create if it doesn''t exist
with touchopen("./tool.run", "r+") as doing_fd:
# Acquire a non-blocking exclusive lock
fcntl.lockf(doing_fd, fcntl.LOCK_EX)
# Read a previous value if present
previous_value = doing_fd.read()
print previous_value
# Write the new value and truncate
doing_fd.seek(0)
doing_fd.write("new value")
doing_fd.truncate()
No sé de ninguna manera elegante de hacer exactamente esto en Ruby. Mi solución probablemente sería crear un archivo temporal, escribir contenido en él y luego cambiarle el nombre al nombre que realmente quería. Esto sobrescribiría el archivo anterior si existe, o crearía el archivo si no existiera. Algo como esto:
orig_filename = ''./whatever_file.log''
temp_filename = ''./.tempfile''
temp_file = File.new(temp_filename, ''w'')
// Write contents to file
temp_file.close
File.rename(temp_filename, orig_filename)
El cambio de nombre generará SystemCallError
si falla por alguna razón.
Puedes leer, escribir y truncar con "a +" (Ruby):
File.open("test.txt", "a+") do |f|
f.print "abc/ndefgh"
f.rewind
p f.read
f.truncate(5)
end
puts File.size("test.txt") #=> 5