PDA

View Full Version : [C] Leggere un file attraverso system calls


Patriche
28-05-2018, 13:12
Come da titolo dovrei leggere un file txt di questo tipo:
3
2 5 + 1
1 2 - 10
2 4 * 3
3 1 / 2

Come posso fare utilizzando solamente read o comunque altre system calls?
Altra cosa, se volessi saltare la prima riga posso tranquillamente usare lseek?
Grazie, purtroppo sono da sempre abituato con fgets e fscanf ed è tutta la mattina che ci sbatto la testa. :confused:

pabloski
28-05-2018, 17:19
system calls, ma di quale sistema operativo?

Patriche
28-05-2018, 17:33
system calls, ma di quale sistema operativo?

Linux, sono su Ubuntu.
La mia idea era un ciclo che contasse gli '/n' per conteggiare il numero di righe presenti nel file e poi usare la read...
Con lseek mi sposto all'inizio della seconda riga e comincio da lì, il problema sta nel mettere giù il tutto in modo efficente

pabloski
28-05-2018, 17:54
Linux, sono su Ubuntu.
La mia idea era un ciclo che contasse gli '/n' per conteggiare il numero di righe presenti nel file e poi usare la read...
Con lseek mi sposto all'inizio della seconda riga e comincio da lì, il problema sta nel mettere giù il tutto in modo efficente

Questo dipende da quale approccio vuoi usare. Per com'è gestito l'I/O dei sistemi operativi moderni, conviene sempre leggere pezzi di file in memoria e poi eventualmente andare a guardare ( in memoria ) dove stanno i ritorni a capo ( e ci sarebbe da gestire eventualmente sia quelli Unix che Windows, cioè \n e \r\n ).

Il problema è che read vuole sapere quanti byte leggere. Ma senza conoscere la posizione dei ritorni a capo come fai? Dovresti scorrere, carattere per carattere, il file??

A quel punto andresti a leggere due volte ogni riga.

pabloski
28-05-2018, 17:57
Linux, sono su Ubuntu.
La mia idea era un ciclo che contasse gli '/n' per conteggiare il numero di righe presenti nel file e poi usare la read...
Con lseek mi sposto all'inizio della seconda riga e comincio da lì, il problema sta nel mettere giù il tutto in modo efficente

Questo dipende da quale approccio vuoi usare. Per com'è gestito l'I/O dei sistemi operativi moderni, conviene sempre leggere pezzi di file in memoria e poi eventualmente andare a guardare ( in memoria ) dove stanno i ritorni a capo ( e ci sarebbe da gestire eventualmente sia quelli Unix che Windows, cioè \n e \r\n ).

Il problema è che read vuole sapere quanti byte leggere. Ma senza conoscere la posizione dei ritorni a capo come fai? Dovresti scorrere, carattere per carattere, il file??

A quel punto andresti a leggere due volte ogni riga.

Patriche
28-05-2018, 18:04
Questo dipende da quale approccio vuoi usare. Per com'è gestito l'I/O dei sistemi operativi moderni, conviene sempre leggere pezzi di file in memoria e poi eventualmente andare a guardare ( in memoria ) dove stanno i ritorni a capo ( e ci sarebbe da gestire eventualmente sia quelli Unix che Windows, cioè \n e \r\n ).

Il problema è che read vuole sapere quanti byte leggere. Ma senza conoscere la posizione dei ritorni a capo come fai? Dovresti scorrere, carattere per carattere, il file??

A quel punto andresti a leggere due volte ogni riga.

Si purtroppo quello era l'unico modo che ero riuscito bene o male a buttare giù. So che non è per niente efficente e fa schifo da vedere ma questa è solo la prima parte di un progetto e confido che il resto venga più scorrevole (riguarderebbe processi e pipe/code di messaggi).
Come potrei evitarlo senza scorrere due volte carattere per carattere?

Patriche
29-05-2018, 09:59
Domanda: ma perche' non leggi direttamente tutto il file in memoria e da li non trovi i breakline? di che grandezze di file stiamo parlando? Io cosi' a naso direi che se siamo sotto il MB e' piu' efficiente leggere tutto subito con un utilizzo minimo di metodi che vanno a chiamare syscalls.

Sicuramente saremo sotto il megabyte, il mio problema era creare un ciclo che mi permettesse la lettura tramite read di tutte le righe del file ad eccezione della prima riga. Ho messo giù un while ma continua a darmi errori.

pabloski
29-05-2018, 10:29
Sicuramente saremo sotto il megabyte, il mio problema era creare un ciclo che mi permettesse la lettura tramite read di tutte le righe del file ad eccezione della prima riga. Ho messo giù un while ma continua a darmi errori.

Essendo il file piccolo e dovendo saltare solo la prima riga, comunque ti conviene leggere tutto il file. Poi vai a cercare il primo \n e quello che c'è prima semplicemente lo scarti.

fano
29-05-2018, 11:26
Per sapere direttamente da C la dimensione in byte del file usa fstat() https://linux.die.net/man/2/fstat a quel punto allochi il buffer puoi usare 3 metodi per fare questo:

1. malloc(), ma ricordati poi di fare free() tutte le volte che fai return o sei fritto
2. alloca(): alloca nello stack quindi la memoria viene liberata automaticamente quando la funzione fa return
3. dynamic allocated array: personalmente è il metodo che preferisco fai semplicemente così:


rc = fstat(fd, &buf);
// controlla SEMPRE gli errori, mi raccomando!

char myArray[buf.st_size];

// procedi a cercare '\n' in myArray


Poi non capisco il senso di andare ad incasinare e non usare fgets() già le API sono limitatissime se ci se la va pure a cercare... poi se è un esercizio di scuola allora alzo le mani :D

Patriche
29-05-2018, 11:30
Essendo il file piccolo e dovendo saltare solo la prima riga, comunque ti conviene leggere tutto il file. Poi vai a cercare il primo \n e quello che c'è prima semplicemente lo scarti.

E fin lì ci siamo... Il problema è proprio la lettura.
Come posso creare un ciclo che mi dica scorri il file?
Usassi una fscanf non ci sarebbero problemi, è con la read che ho difficoltà a metterlo giù. Quale potrebbe essere la mia condizione del while?

Patriche
29-05-2018, 11:52
Per sapere direttamente da C la dimensione in byte del file usa fstat() https://linux.die.net/man/2/fstat a quel punto allochi il buffer puoi usare 3 metodi per fare questo:

1. malloc(), ma ricordati poi di fare free() tutte le volte che fai return o sei fritto
2. alloca(): alloca nello stack quindi la memoria viene liberata automaticamente quando la funzione fa return
3. dynamic allocated array: personalmente è il metodo che preferisco fai semplicemente così:


rc = fstat(fd, &buf);
// controlla SEMPRE gli errori, mi raccomando!

char myArray[buf.st_size];

// procedi a cercare '\n' in myArray


Poi non capisco il senso di andare ad incasinare e non usare fgets() già le API sono limitatissime se ci se la va pure a cercare... poi se è un esercizio di scuola allora alzo le mani :D


Scusa non avevo letto questo :doh:
Mmm... Ora provo a buttarci giù qualcosa vediamo come va.
Si è un progetto scolastico effettivamente, è quella la rottura.
Grazie per l'aiuto in ogni caso, sei stato molto gentile!

pabloski
29-05-2018, 13:44
Scusa non avevo letto questo :doh:
Mmm... Ora provo a buttarci giù qualcosa vediamo come va.
Si è un progetto scolastico effettivamente, è quella la rottura.
Grazie per l'aiuto in ogni caso, sei stato molto gentile!

Mi sorge un dubbio a questo punto. Quella indicata da fano è una funzione della libc, ok un banale wrapper per la relativa syscall, ma quel codice che ha postato non sta invocando direttamente le syscall del kernel.

Nel tuo caso va bene così?

Patriche
29-05-2018, 15:33
Mi sorge un dubbio a questo punto. Quella indicata da fano è una funzione della libc, ok un banale wrapper per la relativa syscall, ma quel codice che ha postato non sta invocando direttamente le syscall del kernel.

Nel tuo caso va bene così?

A sto punto l'importante é leggere sto maledetto file... Non ho ancora potuto provare il discorso dell'array dinamico ma ho già elaborato un'idea... Vediamo se riesco a metterci nel mezzo qualcosa.

fano
29-05-2018, 16:21
Io non penso il prof intendesse davvero le syscall del kernel... manco sono sicuro si possa fare dal C (forse in assembler)... poi la read() internamente fa comunque la syscall.

pabloski
29-05-2018, 17:39
Io non penso il prof intendesse davvero le syscall del kernel... manco sono sicuro si possa fare dal C (forse in assembler)... poi la read() internamente fa comunque la syscall.

Ma infatti è questo il dubbio. Se ha usato il termine syscall, beh, che intendeva? Parecchia gente confonde le funzioni della libc con le syscall e impropriamente le chiama syscall.

Ma questo mistero può svelarlo solo il professore.

Patriche
29-05-2018, 20:04
Ma infatti è questo il dubbio. Se ha usato il termine syscall, beh, che intendeva? Parecchia gente confonde le funzioni della libc con le syscall e impropriamente le chiama syscall.

Ma questo mistero può svelarlo solo il professore.

Conta che è per un progetto di SO, in parole povere al posto di fopen e fclose dovevo usare open e close...poi comunque l'esercizio mirava a creare vari processi figlio e implementare pipe/code di messaggi...quindi utilizzare fork e qualsivoglia...
Diciamo che quella parte è stata spiegata bene mentre l'altra è stata data più per scontato.
Anche perché dai, essendoci le librerie perché farsi del male? :D
Comunque grazie per i consigli e scusate la rottura! Siete stati veramente molto disponibili.

pabloski
30-05-2018, 10:09
Conta che è per un progetto di SO, in parole povere al posto di fopen e fclose dovevo usare open e close...poi comunque l'esercizio mirava a creare vari processi figlio e implementare pipe/code di messaggi...quindi utilizzare fork e qualsivoglia...
Diciamo che quella parte è stata spiegata bene mentre l'altra è stata data più per scontato.
Anche perché dai, essendoci le librerie perché farsi del male? :D


Quindi è il classico esercizio di sistemi operativi. In quel caso si usa ovviamente la libc.

Però è importante ricordare che per "usare le syscall" s'intende richiamare direttamente le funzioni esposte dal kernel, cosa che si fa ( in Linux ) tramite l'interrupt 80h.

fano
31-05-2018, 14:26
Certo che chiamare le classiche funzioni C open(), read(), write() è proprio sbagliato del resto si sa che i Professori in Italia raramente capiscono cosa insegnano :muro:

Sinceramente in quasi 20 anni di programmazione su Linux non ho mai avuto bisogno di usare interrupt 80h per aprire un file :D

pabloski
31-05-2018, 15:46
Certo che chiamare le classiche funzioni C open(), read(), write() è proprio sbagliato del resto si sa che i Professori in Italia raramente capiscono cosa insegnano :muro:


Non sto dicendo questo. Ma se il professore, ad esempio, insegna come interfacciarsi in Assembly col kernel, allora la libc è fuori dall'equazione.

C'è un bellissimo libro al riguardo "Programming from the Ground Up".

Non avendo l'OP specificato il contesto e avendo usato il termine syscall, mi era venuto il dubbio.

WarDuck
31-05-2018, 22:20
Certo che chiamare le classiche funzioni C open(), read(), write() è proprio sbagliato del resto si sa che i Professori in Italia raramente capiscono cosa insegnano :muro:

Sinceramente in quasi 20 anni di programmazione su Linux non ho mai avuto bisogno di usare interrupt 80h per aprire un file :D

Potresti argomentare? :mbe: :rolleyes:

Alla fine della fiera per aprire un file da user space devi per forza arrivare a fare una syscall, c'è poco da fare. Infatti alla fine se vai a vedere fopen() sotto linux chiama open...

Dopodiché oggi ci sono istruzioni dedicate e più efficienti (ad es. su x86 sysenter/sysexit, syscall) di un software interrupt.

fano
02-06-2018, 17:22
Intendevo dire che di certo non è necessario ad andare a scomodare "software interrupt" per aprire un file... almeno non devi andare a farlo direttamente in ASM... che poi open() alla fine faccia quello è ovvio!
fopen() invece fa buffering quindi prima di arrivare alla syscall ci "mette" un po'...

pabloski
02-06-2018, 18:55
Intendevo dire che di certo non è necessario ad andare a scomodare "software interrupt" per aprire un file... almeno non devi andare a farlo direttamente in ASM... che poi open() alla fine faccia quello è ovvio!
fopen() invece fa buffering quindi prima di arrivare alla syscall ci "mette" un po'...

Vabbuò ma l'esercizio poteva invece essere proprio su quello.

E resta il fatto che il termine syscall è stato usato impropriamente.

p.s. dimenticavo che http://man7.org/linux/man-pages/man2/syscall.2.html