Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

311
Visualizações
¿Qué hace realmente abrir un archivo?

En todos los lenguajes de programación (que yo uso al menos), debe abrir un archivo antes de poder leerlo o escribirlo.

Pero, ¿qué hace realmente esta operación abierta?

Las páginas de manual para funciones típicas en realidad no le dicen nada más que 'abre un archivo para leer/escribir':

http://www.cplusplus.com/reference/cstdio/fopen/

https://docs.python.org/3/library/functions.html#open

Obviamente, mediante el uso de la función se puede decir que implica la creación de algún tipo de objeto que facilita el acceso a un archivo.

Otra forma de expresar esto sería, si tuviera que implementar una función open , ¿qué tendría que hacer en Linux?

over 4 years ago · Santiago Trujillo
8 Respostas
Responde à pergunta

0

En casi todos los lenguajes de alto nivel, la función que abre un archivo es un contenedor alrededor de la llamada al sistema del núcleo correspondiente. También puede hacer otras cosas sofisticadas, pero en los sistemas operativos contemporáneos, abrir un archivo siempre debe pasar por el kernel.

Esta es la razón por la que los argumentos de la función de biblioteca fopen , o open de Python, se parecen mucho a los argumentos de la llamada al sistema open(2) .

Además de abrir el archivo, estas funciones suelen configurar un búfer que se utilizará en consecuencia con las operaciones de lectura/escritura. El propósito de este búfer es garantizar que cada vez que desee leer N bytes, la llamada de biblioteca correspondiente devolverá N bytes, independientemente de si las llamadas al sistema subyacente devuelven menos.

No estoy realmente interesado en implementar mi propia función; solo en entender qué diablos está pasando... 'más allá del lenguaje' si se quiere.

En los sistemas operativos similares a Unix, una llamada exitosa para open devuelve un "descriptor de archivo" que es simplemente un número entero en el contexto del proceso del usuario. En consecuencia, este descriptor se pasa a cualquier llamada que interactúe con el archivo abierto y, después de llamar a close , el descriptor deja de ser válido.

Es importante señalar que la llamada a open actúa como un punto de validación en el que se realizan varias comprobaciones. Si no se cumplen todas las condiciones, la llamada falla al devolver -1 en lugar del descriptor, y el tipo de error se indica en errno . Los controles esenciales son:

  • Si el archivo existe;
  • Si el proceso de llamada tiene privilegios para abrir este archivo en el modo especificado. Esto se determina haciendo coincidir los permisos de archivo, la identificación del propietario y la identificación del grupo con las identificaciones respectivas del proceso de llamada.

En el contexto del kernel, tiene que haber algún tipo de mapeo entre los descriptores de archivo del proceso y los archivos abiertos físicamente. La estructura de datos interna que se asigna al descriptor puede contener otro búfer que trata con dispositivos basados en bloques o un puntero interno que apunta a la posición actual de lectura/escritura.

over 4 years ago · Santiago Trujillo Relatório

0

Depende del sistema operativo qué sucede exactamente cuando abre un archivo. A continuación, describo lo que sucede en Linux, ya que le da una idea de lo que sucede cuando abre un archivo y puede consultar el código fuente si está interesado en obtener más detalles. No estoy cubriendo los permisos, ya que haría que esta respuesta fuera demasiado larga.

En Linux, cada archivo es reconocido por una estructura llamada inode . Cada estructura tiene un número único y cada archivo solo recibe un número de inodo. Esta estructura almacena metadatos para un archivo, por ejemplo, tamaño de archivo, permisos de archivo, marcas de tiempo y puntero a bloques de disco, sin embargo, no el nombre del archivo en sí. Cada archivo (y directorio) contiene una entrada de nombre de archivo y el número de inodo para la búsqueda. Cuando abre un archivo, suponiendo que tenga los permisos pertinentes, se crea un descriptor de archivo utilizando el número de inodo único asociado con el nombre del archivo. Como muchos procesos/aplicaciones pueden apuntar al mismo archivo, inode tiene un campo de enlace que mantiene el recuento total de enlaces al archivo. Si un archivo está presente en un directorio, su recuento de enlaces es uno, si tiene un enlace fijo, su recuento de enlaces será dos y si un proceso abre un archivo, el recuento de enlaces se incrementará en 1.

over 4 years ago · Santiago Trujillo Relatório

0

En el centro de esto, cuando se abre para leer, no es necesario que suceda nada sofisticado. Todo lo que necesita hacer es comprobar que el archivo existe y que la aplicación tiene suficientes privilegios para leerlo y crear un identificador en el que pueda emitir comandos de lectura para el archivo.

Es en esos comandos que se enviará la lectura real.

El sistema operativo a menudo obtendrá una ventaja inicial en la lectura al iniciar una operación de lectura para llenar el búfer asociado con el identificador. Luego, cuando realmente hace la lectura, puede devolver el contenido del búfer inmediatamente en lugar de tener que esperar en el disco IO.

Para abrir un archivo nuevo para escribir, el sistema operativo deberá agregar una entrada en el directorio para el archivo nuevo (actualmente vacío). Y nuevamente se crea un identificador en el que puede emitir los comandos de escritura.

over 4 years ago · Santiago Trujillo Relatório

0

Cualquier sistema de archivos o sistema operativo del que quieras hablar está bien para mí. ¡Agradable!


En un ZX Spectrum, inicializar un comando LOAD pondrá el sistema en un bucle cerrado, leyendo la línea de entrada de audio.

El inicio de los datos se indica mediante un tono constante, y luego sigue una secuencia de pulsos largos/cortos, donde un pulso corto es para un 0 binario y uno más largo para un 1 binario ( https://en.wikipedia. org/wiki/ZX_Spectrum_software ). El ciclo de carga estrecha reúne bits hasta que llena un byte (8 bits), lo almacena en la memoria, aumenta el puntero de la memoria y luego regresa para buscar más bits.

Por lo general, lo primero que leería un cargador es un encabezado corto de formato fijo, que indica al menos la cantidad de bytes que se esperan y posiblemente información adicional, como el nombre del archivo, el tipo de archivo y la dirección de carga. Después de leer este breve encabezado, el programa podría decidir si continuar cargando la mayor parte de los datos o salir de la rutina de carga y mostrar un mensaje apropiado para el usuario.

Un estado de fin de archivo se puede reconocer al recibir tantos bytes como se espera (ya sea un número fijo de bytes, cableado en el software o un número variable como el que se indica en un encabezado). Se lanzaba un error si el bucle de carga no recibía un pulso en el rango de frecuencia esperado durante un cierto período de tiempo.


Un poco de historia sobre esta respuesta.

El procedimiento descrito carga datos de una cinta de audio regular, de ahí la necesidad de escanear la entrada de audio (se conecta con un enchufe estándar a las grabadoras). Un comando LOAD es técnicamente lo mismo que open un archivo, pero está físicamente vinculado a cargar el archivo. Esto se debe a que la grabadora no está controlada por la computadora y no puede (con éxito) abrir un archivo pero no cargarlo.

El "bucle cerrado" se menciona porque (1) la CPU, una Z80-A (si la memoria sirve), era realmente lenta: 3,5 MHz, y (2) ¡el Spectrum no tenía reloj interno! Eso significa que tenía que llevar la cuenta con precisión de los estados T (tiempos de instrucción) para cada uno. único. instrucción. dentro de ese ciclo, solo para mantener la sincronización precisa del pitido.
Afortunadamente, esa baja velocidad de la CPU tenía la clara ventaja de que podía calcular la cantidad de ciclos en una hoja de papel y, por lo tanto, el tiempo real que tomarían.

over 4 years ago · Santiago Trujillo Relatório

0

Le sugiero que eche un vistazo a esta guía a través de una versión simplificada de la llamada al sistema open() . Utiliza el siguiente fragmento de código, que es representativo de lo que sucede detrás de escena cuando abre un archivo.

 0 int sys_open(const char *filename, int flags, int mode) { 1 char *tmp = getname(filename); 2 int fd = get_unused_fd(); 3 struct file *f = filp_open(tmp, flags, mode); 4 fd_install(fd, f); 5 putname(tmp); 6 return fd; 7 }

Brevemente, esto es lo que hace ese código, línea por línea:

  1. Asigne un bloque de memoria controlada por el kernel y copie el nombre del archivo desde la memoria controlada por el usuario.
  2. Elija un descriptor de archivo no utilizado, que puede considerar como un índice entero en una lista ampliable de archivos abiertos actualmente. Cada proceso tiene su propia lista de este tipo, aunque el kernel la mantiene; su código no puede acceder a él directamente. Una entrada en la lista contiene la información que utilizará el sistema de archivos subyacente para extraer bytes del disco, como el número de inodo, los permisos de proceso, las banderas abiertas, etc.
  3. La función filp_open tiene la implementación

     struct file *filp_open(const char *filename, int flags, int mode) { struct nameidata nd; open_namei(filename, flags, mode, &nd); return dentry_open(nd.dentry, nd.mnt, flags); }

    que hace dos cosas:

    1. Use el sistema de archivos para buscar el inodo (o, de manera más general, cualquier tipo de identificador interno que use el sistema de archivos) correspondiente al nombre de archivo o la ruta que se pasó.
    2. Cree un struct file con la información esencial sobre el inodo y devuélvalo. Esta estructura se convierte en la entrada en esa lista de archivos abiertos que mencioné anteriormente.
  4. Almacene ("instale") la estructura devuelta en la lista de archivos abiertos del proceso.

  5. Libera el bloque asignado de memoria controlada por el kernel.
  6. Devuelve el descriptor del archivo, que luego se puede pasar a funciones de operación de archivos como read() , write() y close() . Cada uno de estos transferirá el control al núcleo, que puede usar el descriptor de archivo para buscar el puntero de archivo correspondiente en la lista del proceso y usar la información en ese puntero de archivo para realizar la lectura, escritura o cierre.

Si se siente ambicioso, puede comparar este ejemplo simplificado con la implementación de la llamada al sistema open() en el kernel de Linux, una función llamada do_sys_open() . No deberías tener ningún problema para encontrar las similitudes.


Por supuesto, esta es solo la "capa superior" de lo que sucede cuando llama a open() , o más precisamente, es la pieza de código del kernel de más alto nivel que se invoca en el proceso de abrir un archivo. Un lenguaje de programación de alto nivel podría agregar capas adicionales además de esto. Hay muchas cosas que suceden en los niveles inferiores. (Gracias a Ruslan y pjc50 por explicar). Aproximadamente, de arriba a abajo:

  • open_namei() y dentry_open() invocan el código del sistema de archivos, que también forma parte del núcleo, para acceder a metadatos y contenido de archivos y directorios. El sistema de archivos lee bytes sin procesar del disco e interpreta esos patrones de bytes como un árbol de archivos y directorios.
  • El sistema de archivos usa la capa de dispositivo de bloque , nuevamente parte del núcleo, para obtener esos bytes sin procesar de la unidad. (Dato curioso: Linux le permite acceder a datos sin procesar desde la capa de dispositivo de bloque usando /dev/sda y similares).
  • La capa de dispositivo de bloque invoca un controlador de dispositivo de almacenamiento, que también es código kernel, para traducir desde una instrucción de nivel medio como "leer sector X" a instrucciones de entrada/salida individuales en código de máquina. Hay varios tipos de controladores de dispositivos de almacenamiento, incluidos IDE , (S)ATA , SCSI , Firewire , etc., que corresponden a los diferentes estándares de comunicación que podría usar una unidad. (Tenga en cuenta que el nombre es un desastre).
  • Las instrucciones de E/S usan las capacidades integradas del chip del procesador y el controlador de la placa base para enviar y recibir señales eléctricas en el cable que va a la unidad física. Esto es hardware, no software.
  • En el otro extremo del cable, el firmware del disco (código de control incorporado) interpreta las señales eléctricas para hacer girar los platos y mover los cabezales (HDD), o leer una celda ROM flash (SSD), o lo que sea necesario para acceder a los datos en ese tipo de dispositivo de almacenamiento.

Esto también puede ser algo incorrecto debido al almacenamiento en caché . :-P Hablando en serio, hay muchos detalles que he omitido: una persona (no yo) podría escribir varios libros que describan cómo funciona todo este proceso. Pero eso debería darte una idea.

over 4 years ago · Santiago Trujillo Relatório

0

Contabilidad, principalmente. Esto incluye varias comprobaciones como "¿Existe el archivo?" y "¿Tengo los permisos para abrir este archivo para escribir?".

Pero eso es todo sobre el núcleo: a menos que esté implementando su propio sistema operativo de juguete, no hay mucho en lo que profundizar (si es así, diviértase, es una gran experiencia de aprendizaje). Por supuesto, aún debe aprender todos los posibles códigos de error que puede recibir al abrir un archivo, para que pueda manejarlos correctamente, pero generalmente son pequeñas abstracciones agradables.

La parte más importante en el nivel de código es que le brinda un identificador para el archivo abierto, que usa para todas las demás operaciones que realiza con un archivo. ¿No podría usar el nombre de archivo en lugar de este identificador arbitrario? Bueno, claro, pero usar un mango te da algunas ventajas:

  • El sistema puede realizar un seguimiento de todos los archivos que están abiertos actualmente y evitar que se eliminen (por ejemplo).
  • Los sistemas operativos modernos se construyen alrededor de los identificadores: hay toneladas de cosas útiles que puede hacer con los identificadores, y todos los diferentes tipos de identificadores se comportan casi de manera idéntica. Por ejemplo, cuando se completa una operación de E/S asíncrona en un identificador de archivo de Windows, se señala el identificador; esto le permite bloquear el identificador hasta que se señalice, o completar la operación de forma completamente asíncrona. Esperar un identificador de archivo es exactamente lo mismo que esperar un identificador de subproceso (señalado, por ejemplo, cuando finaliza el subproceso), un identificador de proceso (nuevamente, señalado cuando finaliza el proceso) o un socket (cuando se completa alguna operación asíncrona). Igual de importante, los identificadores son propiedad de sus respectivos procesos, por lo que cuando un proceso finaliza inesperadamente (o la aplicación está mal escrita), el sistema operativo sabe qué identificadores puede liberar.
  • La mayoría de las operaciones son posicionales: read desde la última posición en su archivo. Al usar un controlador para identificar una "apertura" particular de un archivo, puede tener varios controladores simultáneos para el mismo archivo, cada uno leyendo desde sus propios lugares. En cierto modo, el identificador actúa como una ventana móvil en el archivo (y una forma de emitir solicitudes de E/S asíncronas, que son muy útiles).
  • Los identificadores son mucho más pequeños que los nombres de archivo. Un identificador suele tener el tamaño de un puntero, normalmente de 4 u 8 bytes. Por otro lado, los nombres de archivo pueden tener cientos de bytes.
  • Los identificadores permiten que el sistema operativo mueva el archivo, aunque las aplicaciones lo tengan abierto; el identificador sigue siendo válido y aún apunta al mismo archivo, aunque el nombre del archivo haya cambiado.

También hay algunos otros trucos que puede hacer (por ejemplo, compartir identificadores entre procesos para tener un canal de comunicación sin usar un archivo físico; en los sistemas Unix, los archivos también se usan para dispositivos y varios otros canales virtuales, por lo que esto no es estrictamente necesario ), pero en realidad no están vinculados a la operación open en sí, por lo que no voy a profundizar en eso.

over 4 years ago · Santiago Trujillo Relatório

0

Básicamente, una llamada para abrir necesita encontrar el archivo y luego registrar lo que sea necesario para que las operaciones de E/S posteriores puedan encontrarlo nuevamente. Eso es bastante vago, pero será cierto en todos los sistemas operativos que se me ocurran inmediatamente. Los detalles varían de una plataforma a otra. Muchas respuestas que ya están aquí hablan de los sistemas operativos de escritorio modernos. He hecho un poco de programación en CP/M, así que voy a ofrecer mi conocimiento sobre cómo funciona en CP/M (MS-DOS probablemente funciona de la misma manera, pero por razones de seguridad, normalmente no se hace así en la actualidad ).

En CP/M tiene una cosa llamada FCB (como mencionó C, podría llamarlo estructura; en realidad es un área contigua de 35 bytes en RAM que contiene varios campos). El FCB tiene campos para escribir el nombre del archivo y un número entero (4 bits) que identifica la unidad de disco. Luego, cuando llama al archivo abierto del núcleo, pasa un puntero a esta estructura colocándolo en uno de los registros de la CPU. Tiempo después, el sistema operativo regresa con la estructura ligeramente modificada. Independientemente de la E/S que realice en este archivo, pasa un puntero a esta estructura a la llamada del sistema.

¿Qué hace CP/M con este FCB? Reserva ciertos campos para su propio uso y los utiliza para realizar un seguimiento del archivo, por lo que es mejor que nunca los toque desde el interior de su programa. La operación Abrir archivo busca en la tabla al principio del disco un archivo con el mismo nombre que el que está en el FCB (el carácter comodín '?' coincide con cualquier carácter). Si encuentra un archivo, copia cierta información en el FCB, incluidas las ubicaciones físicas del archivo en el disco, de modo que las llamadas de E/S posteriores finalmente llamen al BIOS, que puede pasar estas ubicaciones al controlador de disco. En este nivel, los detalles varían.

over 4 years ago · Santiago Trujillo Relatório

0

En términos simples, cuando abre un archivo, en realidad está solicitando al sistema operativo que cargue el archivo deseado (copie el contenido del archivo) desde el almacenamiento secundario a la RAM para su procesamiento. Y la razón detrás de esto (Cargar un archivo) es que no puede procesar el archivo directamente desde el disco duro debido a su velocidad extremadamente lenta en comparación con la RAM.

El comando abrir generará una llamada al sistema que, a su vez, copiará el contenido del archivo desde el almacenamiento secundario (disco duro) al almacenamiento primario (ram).

Y 'Cerramos' un archivo porque el contenido modificado del archivo debe reflejarse en el archivo original que está en el disco duro. :)

Espero que ayude.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda