2011-01-25 11 views
72

Es de conocimiento común en la mayoría de los lenguajes de programación que el flujo para trabajar con archivos es open-use-close. Sin embargo, vi muchas veces en los códigos de rubí sin igual File.open llama, y ​​por otra parte me encontré this gem of knowledge en la documentación de rubí:Ruby's File.open y la necesidad de f.close

de E/S corrientes se cierran automáticamente cuando son reclamados por el recolector de basura.

darkredandyellow IRC amigable tomar sobre el tema:
[17:12] sí, y también, el número de descriptores de archivos se limita por lo general por el sistema operativo
[17:29] Asumo que pueda fácilmente agote los descriptores de archivo disponibles antes de el recolector de basura se limpia. en este caso, es posible que desee utilizar cerrarlos usted mismo. "reclamado por el recolector de basura". significa que el GC actúa en algún momento en el futuro. y es caro muchas razones para cerrar archivos de manera explícita

  1. ¿Necesitamos cerrar explícitamente
  2. Si sí, entonces ¿por qué el autoclose GC?
  3. Si no, ¿por qué la opción?
+0

Su 'conocimiento común' se ha desfasado desde que se inventaron los destructores. – meagar

+1

@meager: ¿Cuándo se inventaron los destructores? –

+0

Solo una nota: Si bien los descriptores de archivos son limitados, al menos en Linux, el límite es bastante alto. – Linuxios

Respuesta

109

vi muchas veces en los códigos de rubí sin igual File.open llamadas

¿Puede dar un ejemplo? Solo veo que en código escrito por novatos que falta "el conocimiento común en la mayoría de los lenguajes de programación es que el flujo para trabajar con archivos es de uso abierto-cerrado".

Los Ruby experimentados cierran sus archivos explícitamente o, más idiomáticamente, usan el formulario de bloque File.open, que automáticamente cierra el archivo por usted. Su implementación básicamente se parece a esto:

def File.open(*args, &block) 
    return open_with_block(*args, &block) if block_given? 
    open_without_block(*args) 
end 

def File.open_without_block(*args) 
    # do whatever ... 
end 

def File.open_with_block(*args) 
    yield f = open_without_block(*args) 
ensure 
    f.close 
end 

Las secuencias de comandos son un caso especial. Los scripts generalmente son tan cortos y utilizan tan pocos descriptores de archivos que simplemente no tiene sentido cerrarlos, ya que el sistema operativo los cerrará de todos modos cuando el script salga.

¿Necesitamos cerrar explícitamente?

Sí.

En caso afirmativo, ¿por qué el GC se cierra automáticamente?

Porque después de que haya recogido el objeto, ya no hay forma de que cierre el archivo y, por lo tanto, se perderían los descriptores de archivos.

Tenga en cuenta que no es el recolector de basura el que cierra los archivos. El recolector de basura simplemente ejecuta los finalizadores de un objeto antes de que lo recopile. Sucede que la clase File define un finalizador que cierra el archivo.

Si no, ¿por qué la opción?

Porque la memoria desperdiciada es barata, pero los descriptores de archivos desperdiciados no lo son. Por lo tanto, no tiene sentido vincular el tiempo de vida de un descriptor de archivo a la duración de algún fragmento de memoria.

Simplemente no puede predecir cuando se ejecutará el recolector de basura. Ni siquiera puede predecir si ejecutará en total: si nunca se queda sin memoria, el recolector de basura nunca se ejecutará, por lo tanto, el finalizador nunca se ejecutará, por lo tanto, el archivo nunca se cerrará.

+1

https://github.com/isaac/sunspot/blob/cell/sunspot/lib/sunspot/rich_document.rb +23 (aunque su número de kernel está abierto y se usa principalmente para el lado HTTP de él, pero lo alcancé con un parámetro de ruta de archivo local, sin embargo ...; todavía estoy tratando de encontrar el tiempo para parchar y request-pull), https://github.com/jnicklas/carrierwave Ctrl + f "File.open" (se da como ejemplo, pero de mala manera ...), y varios otros lugares que no recuerdo.Tengo problemas con el problema debido a los requisitos de estabilidad en mis proyectos ... – clyfe

+3

En este ejemplo, ¿debería elevarse dentro del bloque de rescate? ¿Esto no arrojará un error de tiempo de ejecución si se llama a raise y no hay excepción? –

+0

@JeffStorey: buena captura! 17 meses inadvertidos ... –

0
  1. En caso de que no, o si hay alguna otra falla
  2. Ver 2.
61

Siempre se debe cerrar el archivo de descriptores después de su uso, que también tirar de la cadena. A menudo las personas usan File.open o un método equivalente con bloques para manejar el tiempo de vida del descriptor de archivos. Por ejemplo:

File.open('foo', 'w') do |f| 
    f.write "bar" 
end 

En ese ejemplo, el archivo se cierra automáticamente.

+0

Buen punto. Seguí un error a un script que no llama a File.close. Como resultado, la última línea faltará en algunos archivos de vez en cuando. –

+0

Excepcional. Nunca supe este truco. Al igual que java-8 en ese sentido. Gracias. – sagneta

0

podemos utilizar la función File.read() para leer el archivo en rubí ..... tales como,

file_variable = File.read("index.html") 

en este ejemplo file_variable puede tener el valor total de ese archivo ....

0

Según http://ruby-doc.org/core-2.1.4/File.html#method-c-open

sin bloque asociado, File.open es sinónimo de nuevo ::. Si se proporciona el bloque de código opcional , se pasará el archivo abierto como argumento y el objeto Archivo se cerrará automáticamente cuando finalice el bloque . El valor del bloque se devolverá desde File.open.

Por lo tanto, se cerrará automáticamente cuando el bloque termina: D

Cuestiones relacionadas