Créer un fichier vide en C. [Résolu]

Créer un fichier vide en C. [Résolu] - C - Programmation

Marsh Posté le 07-12-2005 à 21:03:46    

Bonjour,
Je souhaite allouer une certaine place a un fichier, et le remplir par la suite.
Mettons que je veux faire un fichier vide de 200 octets , je fais
 

Code :
  1. int fd;
  2. if((fd = open("data2",O_CREAT)) == -1)
  3.       erreur("open for allocating\n" );
  4. lseek(fd,199,SEEK_SET);
  5. write(fd,"0",1);
  6. close(fd);


 
ca me cree bien un fichier data2 mais de 0 octets :S j'avais d'abord essayer un lseek de 200 sans rien écrire,  
mais cela ne marchait pas non plus ...
 
je sais que c'est une question trés bête, ne me linchez pas please :)
merci

Message cité 1 fois
Message édité par meumeul le 08-12-2005 à 17:09:37
Reply

Marsh Posté le 07-12-2005 à 21:03:46   

Reply

Marsh Posté le 07-12-2005 à 22:00:56    

Tu peux utiliser truncate ou ftruncate, le prototype doit etre du truncate( nom_du_fichier, longueur ),  si la taille du fichier ou du descripteur spécifié est inférieure à longueur le fichier est étendu et la différence entre l'ancienne EOF et la nouvelle est matérialisée par un trou (ie des 0 qui ne sont pas alloues physiquement sur le disque)

Reply

Marsh Posté le 07-12-2005 à 22:05:54    

meumeul a écrit :

Je souhaite allouer une certaine place a un fichier, et le remplir par la suite.
Mettons que je veux faire un fichier vide de 200 octets , je fais


  • Un fichier vide est un fichier de 0 octets.
  • Un fichier avec 200 octets dedans (à quelle valeur ?) n'est évidemment pas vide.


Je pense qu'il y a un problème de conception quelque part. Que veux tu faire exactement ?
 
Sinon, pour créer un fichier de 200 octets (à 0, par exemple) :  


#include <stdio.h>
 
int main (void)
{
   FILE *fp = fopen ("data.txt", "w" );
 
   if (fp != NULL)
   {
      char a[200] = {0};
 
      fwrite (a, sizeof a, 1, fp);
      fclose (fp), fp = NULL;
   }
   return 0;
}



 Le volume dans le lecteur C s'appelle 427409
 Le numéro de série du volume est 8873-ADFB
 
 Répertoire de C:\dev\forums\OP
 
07/12/2005  22:05               200 data.txt
               1 fichier(s)              200 octets
               0 Rép(s)  155 849 830 400 octets libres


Message édité par Emmanuel Delahaye le 07-12-2005 à 22:06:47

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 07-12-2005 à 22:28:35    

meumeul, ton code est bon a deux choses pres :
 
1) C'est O_CREAT | O_WRONLY, qu'il faut utiliser, pas seulement O_CREAT
 
2) write prend en argument l'adresse du buffer que tu veux ecrire, pas directement les donnees que tu veux ecrire. Donc c'est write(fd, &c, 1) avec char c = 0, pas write(fd,"0",1).
 
Mais attention, le resultat n'est pas forcement ce a quoi tu t'attend. Suivant l'OS et suivant l'offset du lseek (i.e. avec un grand offset), tu peux te retrouver avec un "sparse file". Ca ne fait aucune difference en pratique (quand tu le lit, tu vois ce que tu as ecrit, et des 0 ou tu n'as pas ecrit), mais tout le fichier ne correspond pas forcement a des donnees sur le disque. Autrement dit ls -l te donnera la bonne taille (celle du lseek + 1), mais le fichier occupe moins de place que ca sur le disque.
 
Demonstration :

Code :
  1. #include <fcntl.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. int
  5. main()
  6. {
  7.         int fd;
  8.         char c = 'a';
  9.         fd = open("sparse_file", O_CREAT | O_WRONLY);
  10.         if (fd == -1) {
  11.                 perror("open" );
  12.                 return 1;
  13.         }
  14.         if (sizeof c != write(fd, &c, sizeof c)) {
  15.                 perror("write 1" );
  16.                 return 1;
  17.         }
  18.         if (-1 == lseek(fd, 100000000, SEEK_SET)) {
  19.                 perror("lseek" );
  20.                 return 1;
  21.         }
  22.         if (sizeof c != write(fd, &c, sizeof c)) {
  23.                 perror("write 2" );
  24.                 return 1;
  25.         }
  26.         return 0;
  27. }


# ls -l sparse_file  
-rwsr-x---   1 root     system    100000001 Dec  7 14:59 sparse_file
# du -k sparse_file  
8       sparse_file


Dans l'exemple ci-dessus on voit que le fichier fait bien 100Mo, mais seulement deux blocs sont alloues sur le disque (8Ko, un bloc etant 4Ko sur ma machine). Par contre si je le lis, je vois bien mon 'a', un autre 'a' 100Mo plus loin, et des 0 entre.

Message cité 2 fois
Message édité par matafan le 07-12-2005 à 22:42:09
Reply

Marsh Posté le 07-12-2005 à 23:02:51    

matafan a écrit :

meumeul, ton code est bon a deux choses pres :
 
1) C'est O_CREAT | O_WRONLY, qu'il faut utiliser, pas seulement O_CREAT
 
2) write prend en argument l'adresse du buffer que tu veux ecrire, pas directement les donnees que tu veux ecrire. Donc c'est write(fd, &c, 1) avec char c = 0, pas write(fd,"0",1).
 
Mais attention, le resultat n'est pas forcement ce a quoi tu t'attend. Suivant l'OS et suivant l'offset du lseek (i.e. avec un grand offset), tu peux te retrouver avec un "sparse file". Ca ne fait aucune difference en pratique (quand tu le lit, tu vois ce que tu as ecrit, et des 0 ou tu n'as pas ecrit), mais tout le fichier ne correspond pas forcement a des donnees sur le disque. Autrement dit ls -l te donnera la bonne taille (celle du lseek + 1), mais le fichier occupe moins de place que ca sur le disque.
 
Demonstration :

Code :
  1. #include <fcntl.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. int
  5. main()
  6. {
  7.         int fd;
  8.         char c = 'a';
  9.         fd = open("sparse_file", O_CREAT | O_WRONLY);
  10.         if (fd == -1) {
  11.                 perror("open" );
  12.                 return 1;
  13.         }
  14.         if (sizeof c != write(fd, &c, sizeof c)) {
  15.                 perror("write 1" );
  16.                 return 1;
  17.         }
  18.         if (-1 == lseek(fd, 100000000, SEEK_SET)) {
  19.                 perror("lseek" );
  20.                 return 1;
  21.         }
  22.         if (sizeof c != write(fd, &c, sizeof c)) {
  23.                 perror("write 2" );
  24.                 return 1;
  25.         }
  26.         return 0;
  27. }


# ls -l sparse_file  
-rwsr-x---   1 root     system    100000001 Dec  7 14:59 sparse_file
# du -k sparse_file  
8       sparse_file


Dans l'exemple ci-dessus on voit que le fichier fait bien 100Mo, mais seulement deux blocs sont alloues sur le disque (8Ko, un bloc etant 4Ko sur ma machine). Par contre si je le lis, je vois bien mon 'a', un autre 'a' 100Mo plus loin, et des 0 entre.


 
Hum... avoir un chmod aléatoire sur un fichier lors de sa création n'est pas franchement une bonne idée (surtout que dans ton cas ça a donné un setuid sur un fichier appartenant à "root" !!!)
=> fd = open("sparse_file", O_CREAT | O_WRONLY, 0644);
 
Ou bien, pour vraiment être rigoureux
=> fd = open("sparse_file", O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 

Message cité 1 fois
Message édité par Sve@r le 08-12-2005 à 12:12:45
Reply

Marsh Posté le 08-12-2005 à 00:06:11    

Exact, oublie de ma part. En fait au debut j'avais pas de O_CREAT dans mon code, donc pas besoin de mode... Puis j'ai ajoute O_CREAT en oubliant d'ajouter le mode.

Reply

Marsh Posté le 08-12-2005 à 12:08:13    

matafan a écrit :


Code :
  1. if (sizeof c != write(fd, &c, sizeof c)) {
  2. ...
  3. }




 
Ne vaut-il pas mieux comparer "if (write(...) < 0)" ???


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 08-12-2005 à 15:49:14    

Sve@r a écrit :

Hum... avoir un chmod aléatoire sur un fichier lors de sa création n'est pas franchement une bonne idée (surtout que dans ton cas ça a donné un setuid sur un fichier appartenant à "root" !!!)
=> fd = open("sparse_file", O_CREAT | O_WRONLY, 0644);
 
Ou bien, pour vraiment être rigoureux
=> fd = open("sparse_file", O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);


 
trés rigoureuse remarque, je n'avais aucun droit sur ce fichier, et je ne captais pas pourquoi ...
merci, ca marche nickel. je vais essayer de le réouvrir et d'ecrire des blocs un peu partout dedans  
maintenant...

Reply

Marsh Posté le 08-12-2005 à 17:09:22    

Ok j'ai reussi à faire tout ce que je voulais, merci pour votre aide, tout n'était qu'en gros, une histoire de droits ... Merci pour les precision quand aux tailles des fichiers.
 
++

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed