Newsgroup: it.comp.lang.c
Titolo: ! File modalita' binaria read and write!???

Salve,
aprendo un file : pf=fopen(argv[1],"r+b") non riesco a scrivere! Ho provato
con varie sigle rb+ r+b +rb, mah!
Con:
while(!feof(pf)){
    c=fgetc(pf)+1;
    if(!feof(pf)) fputc(c,pf);
}
In questo modo vorrei ottenere argv[1] con i caratteri shiftati di 1 a->b,
m->n etc.
Siccome non funziona ho provato cose tipo:
while(!feof(pf)){
    pos=ftell(pf)
    c=fgetc(pf)+1;
    fseek(pf,pos,SEEK_SET);
    if(!feof(pf)) fputc(c,pf);
}
Pensando che il problema fosse che ad ogni ciclo while pf avanzasse di 2 e
non di uno!
Ponendo come problema di esempio, non e' ovviamente quello che sto facendo:
prendi c e scrivi nello stesso punto ++c, come potrei fare?
Vi ringrazio anticipatamente,
Alex
lan...@tin.it

prendi c e scrivi nello stesso punto ++c, come potrei fare?
Leggilo in memoria e sovrascrivilo a segmenti.
Non ti conviene eseguire una fseek() in quel modo.

...


e mi si blocca il tutto! boh!
L'ho provato anch'io e, a parte che non ho l'errore irreversibile e
non si blocca nulla, funziona come da te : non scrive un bel nulla nel
file (provato con Borland TC++ 3.0)
ciao

>>      fputc( c+1, pf ) ;
                     ^^^
bisogna scrivere su un altro file.

bisogna scrivere su un altro file.
OK. A questo punto pero' mi chiedo :
- che senso ha aprire il file con "a+" se poi le varie funzioni non ce
la fanno a scrivere nel file
- per quale ragione c'e' questo problema
- e' scritto da qualche parte che non si puo' fare fputc e fgetc sullo
stesso file ? Il K&R (che non possiedo) cosa dice ? Esiste qualcosa di
piu' autorevole del K&R (es: qualche documenti ISO)
- e, per finire, perche' write (che pero' e' solo DOS) funziona bene ?
ciao

Se apri un file esistente con "r+b" ti assicuro che puoi
fare fread() e fwrite() sullo stesso file. la fwrite() si puo'
fare anche se feof(fp) e' vera, fread() ovviamente non assegna
alcun valore se feof() e' vera. Lo standard diche che non
si possono fare letture e scritture sullo stesso flusso aperto
se tra di esse non si frappone chiamata a fflush(), fseek()
o rewind(), questo perche' chi ha redatto lo standard ha ipotizzato
che gli sviluppatori potessero usare un unico buffer. 
Su linux pero' funziona lo stesso. Non funzione piu' invece
sostituendo fread() e fwrite() con fgetc() e fputc(). Non so se
e' regolare, ma forse ha a che vedere che queste ultime sono
progettate per flussi line buffered e non block buffered come
i files aperti con "b" (binario) E' solo una ipotesi.
Prova anche tu a sostituire tutto con fread() e fwrite() e, per
ragioni di portabilita', fai in modo che tra di esse vi sia
sembre una fflush() o fseek().
ciao.

 - e, per finire, perche' write (che pero' e' solo DOS) funziona bene ?
Forse intendevi la funzione fwrite()? E' standard, non è solo per DOS.
EMG

- e, per finire, perche' write (che pero' e' solo DOS) funziona bene ?
Perche' non e' standard (leggi: di basso livello) : cioe' non
bufferizzata.

 ciao
Lo standard ANSI del C stabilisce che un file aperto sia in lettura che
in scrittura richiede una chiamata ad una funzione di posizionamento
prima di passare da letture a scritture o viceversa. Perchè questo sia
stato lasciato al programmatore invece che maneggiato internamente nelle
funzioni di libreria è alla fine uno dei misteri del C, o se preferisci
un tratto della filosofia C, dove il programmatore sa quello che deve
fare ecc.ecc.
Nel tuo caso, lavorare sul file eseguendo un fseek ogni int è
assolutamente pesante.
Forse va chiarito che quello a cui lo standard ANSI si riferisce in
questo contesto non è il file inteso come elemento del filesystem, bensì
strettamente il dato FILE *. Puoi benissimo operare come desideri tu
purchè tu apra non una ma 2 volte lo stesso file, usando 
FILE *f1, *f2;
e ad esempio lavorando con f1 in lettura e con f2 in scrittura. E'
assolutamente consigliabile.
write() e read() non rientrano nell'ANSI, e come tali possono anche
essere dimostrare differenti comportamenti su differenti piattaforme.
Ovviamente io non posso sapere come si comportano in tutti i casi, in
realtà l'unica cosa che ti posso dire è che su sistemi Un*x (read() e
write() rientrano in POSIX) non funzionerebbero nel modo in cui dici tu,
in quanto solitamente in questi ambienti il puntatore al file offset,
gestito internamente dal sistema e invisibile all'utente, è unico e non
distinto per lettura e scrittura. 
ciao.

 file.
Senza offesa, ma questo non c'entra niente col caso in questione. Il
problema è che l'ANSI C lascia al programmatore l'onere di gestire
l'offset nel file (che è unico sia per le letture che per le scritture)
obbligando ad usare una funzione di posizionamento passando da una
lettura ad una scrittura o viceversa. La stdio è fatta così.
Che non c'entrino i buffer lo si può vedere riscrivendo quel frammento
di codice impiegando l' I/O low-level di read() e write(): almeno in
Un*x quella roba non funziona, e non c'è buffer di mezzo. Che vada in
DOS può essere benissimo, non lo so, in ambienti Un*x non va. Non è roba
ANSI e può variare tra DOS e Un*x.
Il problema semplicemente è che quel codice assume che le scritture e le
letture si possano muovere indipendentemente sullo stesso FILE *, questo
contraddice l'ANSI C, supponendo implicitamente che il sistema o le
librerie gestiscano in modo trasparente un offset per le scritture ed
una per le letture, cosa che l'ANSI C non fa (e neppure i sistemi Un*x).
Non occorre necessariamente leggere il file a blocchi in memoria, anche
se non è un metodo cattivo. Dato che prima leggiamo e poi scriviamo e
che entrambe le operazioni vanno nella stessa direzione senza
variazioni, direi che è sufficiente maneggiare 2 diversi FILE *. Non ho
provato, ma mi pare che il ragionamento fili.
Ciao a tutti.

letture si possano muovere indipendentemente sullo stesso FILE *, 
Non e' vero : il codice in questione utilizza sempre lo stesso
puntatore.

distinto per lettura e scrittura. 
In nessun sistema questo puntatore e' distinto.

 puntatore.
Forse non sono stato chiaro. Usa lo stesso FILE *. Come sai bene, un
dato FILE *f č un puntatore ad una struttura utilizzata
nell'implementazione interna della libreria stdio. Dei dettagli di tale
struttura il programmatore C ANSI-conformant non si deve curare. Il
codice scritto originariamente da spaceace, per funzionare
correttamente, assume che fput(c, pf) vada a riscrivere ciň che
fgetc(pf) ha letto subito prima, incrementato di 1. Questo algoritmo,
senza riposizionamento, implicitamente assume che l'implementazione
della struttura FILE preveda un puntatore (_interno_alla_struttura_)
all'offset di scrittura e un altro all'offset di lettura. Questa
assunzione non č lecita. Per questo non funziona.
ciao.

 In nessun sistema questo puntatore e' distinto.
Se hai qualche solida ragione per affermare che in nessun sistema al
mondo questo puntatore in realtà è "doppio", ti sarei sinceramente grato
se me la illustrassi.
Personalmente, ragionando in modo superficiale, per carità, non vedo
nessuna difficoltà concetttuale ad implementare una versione della stdio
che gestisca 2 puntatori _interni_ (non accessibili al programmatore)
all'offset rispettivamente di scrittura e di lettura.
sinceramente curioso, ciao.

>, mentre in realtà nella frase che hai estratto dal mio precedente post parlavo di write() e di read(). Ancora meglio, non vedo difficoltà concettuali a maneggiare un file descriptor con un offset di scrittura separato dal quello di lettura (enrambi ,sempre, non accessibili al programmatore). In più facendolo non avrei problemi ANSI.
Trovo veramente possibile che esistano sistemi dove questo è
implementato realmente.
ciao.

assunzione non č lecita. Per questo non funziona.
Il codice scritto da spaceace implementava il riposizionamento :
while(!feof(pf)){
    pos=ftell(pf)
    c=fgetc(pf)+1;
    fseek(pf,pos,SEEK_SET); <------------------------------
    if(!feof(pf)) fputc(c,pf);
}

all'offset rispettivamente di scrittura e di lettura.
Certo, ma non servirebbe a nulla (oltre che essere una fonte di bug) e
quindi non viene implementato.

 In nessun sistema questo puntatore e' distinto.
Nelle fstream del C++ si.
EMG

 Il codice scritto da spaceace implementava il riposizionamento :
E' una battuta?
ciao.

 quindi non viene implementato.
Vabbè. Ho le mie buone ragioni per non essere d'accordo, ma non voglio
polemizzare nè intasare il group.
ciao.

Forse intendevi la funzione fwrite()? E' standard, non è solo per DOS.
No, intendevo write che nel Turbo C e' definita come :
  int write(int handle, void *buf, unsigned len);
Secondo l'help e' un funzione che esiste sia in DOS che in UNIX ma non
e' ANSI.
ciao

Lo standard dice
Mi togli una curiosita' ? Quando dici "lo standard dice" e' perche'
l'hai veramente letto dal libro ufficiale oppure perche' l'hai letto
su qualche altro libro magari autorevole come il K&R ?
Te lo chiedo perche', per curiosita', ho cercato in rete se c'era il
testo ufficiale ed ho trovato solo il posto dove poterlo comprare :
http://www.iso.ch/cate/d29237.html
 
ISO/IEC 9899:1999
Programming languages -- C (available in English only)
Edition: 2 (Monolingual) 
Number of pages: 538
Price code: XL (cioe' 334 Franchi Svizzeri)
Technical committee / subcommittee: JTC 1/SC 22
ICS: 35.060
Stage: 60.60
Stage date: 1999-12-16
Considerando quanto costa, che e' solo in inglese e che lo vende solo
la ISO mi sembra strano che tutti ce l'abbiano
Comunque, nella pagina delle FAQ inglesi
(
http://www.eskimo.com/~scs/C-faq/s11.html
) dicono :
The text of the Rationale (not the full Standard) can be obtained by
anonymous ftp from 
ftp.uu.net
 (see question 18.16) in directory
doc/standards/ansi/X3.159-1989, and is also available on the web at
http://www.lysator.liu.se/c/rat/title.html
.
E, leggendo il Rationale, si trova scritto
(
http://www.lysator.liu.se/c/rat/d9.html#4-9-5-3
) :
A change of input/output direction on an update file is only allowed
following a fsetpos, fseek, rewind, or fflush operation, since these
are precisely the functions which assure that the I/O buffer has been
flushed.  
Se interessa, nelle FAQ c'e' anche un riferimento alla pagina dove
vengono elencati gli errori contenuti nei libri di H.Schildt :
http://www.lysator.liu.se/c/schildt.html
.
ciao

file.
Come ho detto, non e' un problema, solo che se l'avessero scritto
nell'help o nel manuale sarebbe stata una bella cosa.
ciao

O di flushing.
Ma non si era detto che la fflush funziona solo in output ? Pertanto
la sequenza fread-fflush-fwrite non equivale a fread-fwrite ?
ciao

 Pensando che il problema fosse che ad ogni ciclo while pf avanzasse di 2 e
non di uno!
Poi il thread diventa lunghissimo, e si discute tra noi...
Infine, si può fare a meno di files temporanei o di fflush e compagnia
ad ogni ciclo semplicemente usando FILE *f1 e FILE *f2, aprendo 2 volte
lo stesso file, e scrivendo sempre con f2, leggendo solo con f1. Non
funziona in generale, ma in questo caso sì. E non spreca risorse visto
che è bufferato. L'ho scritto nel mio primo post.
ciao.

[root@fokhouse /tmp]# cat prova.c
#include <stdio.h>
int main(int argc, char *argv[])
{
        int c;
        FILE *fp;
        if ((fp = fopen(argv[1], "r+")) == NULL) exit(1);
        while ((c = fgetc(fp)) != EOF) {
                if (c == '\n') continue; /* per comodita' */
                fseek(fp, -1, SEEK_CUR);
                fputc(c + 1, fp);
                fflush(fp);
        }
        fclose(fp);
        return 0;
}
[root@fokhouse /tmp]# gcc -o prova prova.c -Wall -ansi -pedantic
[root@fokhouse /tmp]# cat >testo
abcdefgh
ilmnopqrst
uvz
[root@fokhouse /tmp]# ./prova testo
[root@fokhouse /tmp]# cat testo
bcdefghi
jmnopqrstu
vw{
[root@fokhouse /tmp]#
Ciao ciao,
Andrea
-- 
"...Unix, MS-DOS, and Windows NT (also known as the Good, the Bad, and 
 the Ugly)."
(by Matt Welsh)

 
http://www.iso.ch/cate/d29237.html
Il libro su cui l' ho letto e' il Mangrovis (McGraw Hill). Cita
lo standard, ma non so dire se le sue interpretazioni siano opinabili.
Comunque per me e' tutto: non ho altri libri sul C. Il resto e'
man 2 funzione o info libc
ciao.