Lecture et écriture de données dans un fichier

epetit91epetit91 Membre
février 2012 modifié dans API AppKit #1
Bonsoir,



Je cherche à  faire la chose suivante :



Ouvrir un fichier

Lire une structure de données (des short) dans ce fichier

Refermer le fichier



Créer et ouvrir un nouveau fichier

Ecrire le contenu de la structure dans ce fichier

Refermer le fichier



J'ai écris le code suivant :



Définition de la structure :



typedefstruct_EnteteDonnees

{

short data1;

short data1;

short data1;

short data1;

short data1;

} EnteteDonnees;



Code :





- (void) InfoEntete

{

NSFileHandle *file;

EnteteDonnees entete;

NSUInteger tailleData;



// Ouverture du fichier d'entrée

file = /color][color=#6f41a8]NSFileHandle[/color][color=#000000] [/color]fileHandleForReadingAtPath[color=#000000]:[[[/color][color=#6f41a8]NSUserDefaults[/color][color=#000000] [/color]standardUserDefaults[color=#000000 stringForKey:@InputFilePath]];



// Le fichier est introuvable

if (nil == file)

{

NSRunCriticalAlertPanel(NSLocalizedString(@erreur ouverture fichier, nil),

NSLocalizedString(@erreur fichier introuvable, nil), @OK, nil, nil,

[color=#6f41a8]NSUserDefaults[/color] [color=#3d2380]standardUserDefaults[/color stringForKey:@InputFilePath]);

return;

}



tailleData = sizeof(EnteteDonnees);

[[file readDataOfLength:tailleData] getBytes:&entete length:tailleData];

[file closeFile];

}





Ce code fonctionne pour la lecture mais je ne suis pas certain de bien procéder.



En revanche, je ne sais pas comment réaliser la partie de création et d'écriture dans un autre fichier contenu dans la clé "OutputFilePath".



Quelqu'un pourrait-il m'aider ?



Je suis sous OSX Lion.



Avec tous mes remerciements.

Réponses

  • Un truc dans ce genre là  ? :


    <br />
    #import &quot;AppDelegate.h&quot;<br />
    <br />
    // pour tes besoins :<br />
    //#define kInputFilePath  [[NSUserDefaults standardUserDefaults] stringForKey:@&quot;InputFilePath&quot;]<br />
    //#define kOutputFilePath  [[NSUserDefaults standardUserDefaults] stringForKey:@&quot;InputFilePath&quot;]<br />
    <br />
    // pour les tests :<br />
    #define kInputFilePath  @&quot;~/Desktop/ListOfShorts.txt&quot;<br />
    #define kOutputFilePath  @&quot;~/Desktop/OtherListOfShorts.txt&quot;<br />
    <br />
    @implementation AppDelegate<br />
    <br />
    @synthesize window = _window;<br />
    @synthesize array;<br />
    <br />
    - (void)dealloc<br />
    {<br />
    	[super dealloc];<br />
    }<br />
    <br />
    - (void)infoEntete<br />
    {<br />
       NSString  *path = [kInputFilePath stringByExpandingTildeInPath];<br />
       NSError   *error = nil;<br />
       // chargement à  partir du fichier texte<br />
       NSString  *string = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&amp;error];<br />
       if (error)<br />
       {<br />
    	  [NSApp presentError:error];<br />
    	  return;<br />
       }<br />
       self.array = [string componentsSeparatedByString:@&quot;&#092;n&quot;];<br />
    <br />
       NSLog(@&quot;&#092;ninfos entete : &#092;n%@&quot;, self.array);<br />
    }<br />
    <br />
    - (void)writeArrayInFile<br />
    {<br />
       NSString *outputString = [self.array componentsJoinedByString:@&quot;&#092;n&quot;];<br />
       NSError  *error = nil;<br />
       NSString  *path = [kOutputFilePath stringByExpandingTildeInPath];<br />
    <br />
    // écriture dans un autre fichier texte<br />
       if (&#33;[outputString writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&amp;error])<br />
    	 [NSApp presentError:error];<br />
    }<br />
    <br />
    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification<br />
    {<br />
       [self infoEntete];<br />
    }<br />
    <br />
    - (void)applicationWillTerminate:(NSNotification *)notification<br />
    {<br />
       [self writeArrayInFile];<br />
    }<br />
    <br />
    @end<br />
    




    J'ai pri un fichier texte dans l'exemple, pour stocker la liste de shorts (séparés par un CR : @\n) sous forme de strings (que tu peux transformer en short, une fois chargées).

    Mais ce pourrait aussi être un fichier "ListOfShorts.plist" (situé par exemple dans le bundle de l'appli) contenant un array de strings ou de Numbers que tu charges comme suit :


    <br />
    - (void)infoEntete<br />
    {<br />
       NSString *path = [[NSBundle mainBundle] pathForResource:@&quot;ListOfShorts&quot;<br />
    			  ofType:@&quot;plist&quot;];<br />
       self.array =[NSArray arrayWithContentsOfFile:path];<br />
    }<br />
    




    NSString, NSArray, NSData possèdent des Class methods de lecture dans un fichier, de la forme :

    string(array, data)WithContentsOfFile:path



    et des instances methods pour l'écriture dans un fichier de la forme :

    writeToFile:path atomically:yesOrNo
  • epetit91epetit91 Membre
    janvier 2012 modifié #3
    Merci beaucoup pour ta réponse rapide.

    Comment est-ce que je fais la transition entre le fait que tu lises et écrives une chaà®ne et le fait que je veuille lire et écrire la structure que j'ai définie dans mon exemple.

    Ce que je ne vois pas non plus c'est comment tu ouvres le fichier d'entrée (ce que j'ai écrit dans mon exemple est-il correct image/huh.gif' class='bbc_emoticon' alt='???' />) et comment tu crées et ouvres le fichier de sortie.

    Ce que je comprends dans ton exemple c'est que le fichier de sortie est déjà  présent sur le disque.

    Merci encore et désolé pour ces questions peut être triviales pour certains...
  • Comment est-ce que je fais la transition entre le fait que tu lises et écrives une chaà®ne et le fait que je veuille lire et écrire la structure que j'ai définie dans mon exemple.




    tu renseignes les valeurs dans la structure avec les données que tu as chargées


    Ce que je ne vois pas non plus c'est comment tu ouvres le fichier d'entrée (ce que j'ai écrit dans mon exemple est-il correct image/huh.gif' class='bbc_emoticon' alt='???' />)




    cette seule ligne ouvre le fichier d'entrée (qui est sur le bureau pour l'exemple), lit les données, les stocke dans une string et ferme le fichier :
    <br />
    NSString  *string = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&amp;error];<br />
    



    Ce que je comprends dans ton exemple c'est que le fichier de sortie est déjà  présent sur le disque.




    non il est crée et rempli avec la outputString par la ligne :
    <br />
    [outputString writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&amp;error]<br />
    
  • L'objective C reste du C, donc fopen/fread/fwrite/fclose fonctionne très bien pour lire une structure C...
  • Avec la manipulation des bytes en Cocoa dans la classe NSData, avec toujours une seule ligne de code pour lire ou pour écrire les datas dans un fichier :


    <br />
    #import &quot;AppDelegate.h&quot;<br />
    <br />
    // pour tes besoins :<br />
    //#define kInputFilePath  [[NSUserDefaults standardUserDefaults] stringForKey:@&quot;InputFilePath&quot;]<br />
    //#define kOutputFilePath  [[NSUserDefaults standardUserDefaults] stringForKey:@&quot;InputFilePath&quot;]<br />
    <br />
    // pour les tests :<br />
    #define kInputFilePath  @&quot;~/Desktop/ListOfShorts.entete&quot;<br />
    #define kOutputFilePath  @&quot;~/Desktop/OtherListOfShorts.entete&quot;<br />
    <br />
    @implementation AppDelegate<br />
    <br />
    @synthesize window = _window;<br />
    @synthesize array;<br />
    <br />
    typedef struct _EnteteDonnees<br />
    {<br />
    short data1;<br />
    short data2;<br />
    short data3;<br />
    short data4;<br />
    short data5;<br />
    } EnteteDonnees;<br />
    <br />
    - (void)dealloc<br />
    {<br />
       [super dealloc];<br />
    }<br />
    - (void)infoEntete<br />
    {<br />
       EnteteDonnees entete;<br />
    <br />
       NSString  *path = [kInputFilePath stringByExpandingTildeInPath];<br />
       NSData   *data = [NSData dataWithContentsOfFile:path];<br />
       if (&#33;data)<br />
    	 NSRunAlertPanel(@&quot;Erreur&quot;, @&quot;Erreur lors de la lecture du fichier %@&quot;, @&quot;OK&quot;, nil, nil, path);<br />
       else<br />
       {<br />
    	 [data getBytes:&amp;entete length:[data length]];<br />
    	 NSLog(@&quot;&#092;n&#092;nLecture de entete :&#092;ndata1 : %i&#092;ndata2 : %i&#092;ndata3 : %i&#092;ndata4 : %i&#092;ndata5 : %i&quot;,<br />
    	 entete.data1, entete.data2, entete.data3, entete.data4, entete.data5);<br />
       }<br />
    }<br />
    <br />
    - (void)writeArrayInFile<br />
    {<br />
       EnteteDonnees entete;<br />
       entete.data1 = 1;<br />
       entete.data2 = 22;<br />
       entete.data3 = 107;<br />
       entete.data4 = 4;<br />
       entete.data5 = 15;<br />
    <br />
       NSLog(@&quot;&#092;n&#092;nEcriture de entete :&#092;ndata1 : %i&#092;ndata2 : %i&#092;ndata3 : %i&#092;ndata4 : %i&#092;ndata5 : %i&quot;,<br />
    	entete.data1, entete.data2, entete.data3, entete.data4, entete.data5);<br />
    <br />
       NSString  *path = [kOutputFilePath stringByExpandingTildeInPath];<br />
       NSData   *data = [NSData dataWithBytes:&amp;entete length:sizeof(entete)];<br />
       if (&#33;[data writeToFile:path atomically:YES])<br />
    	 NSRunAlertPanel(@&quot;Erreur&quot;, @&quot;Erreur lors de l&#39;ecriture du fichier %@&quot;, @&quot;OK&quot;, nil, nil, path);<br />
    }<br />
    <br />
    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification<br />
    {<br />
       [self infoEntete];<br />
    }<br />
    <br />
    - (void)applicationWillTerminate:(NSNotification *)notification<br />
    {<br />
       [self writeArrayInFile];<br />
    }<br />
    <br />
    @end<br />
    
  • Cf. le nom du forum : CocoaCafé
  • Merci beaucoup uocram pour ton aide. C'est maintenant beaucoup plus clair.



    Merci également Smy pour ta remarque. Je préfère, dans la mesure du possible, écrire du "pur Cocoa" car c'est pour moi aussi un moyen de progresser surtout quand on a la chance d'avoir un forum aussi compétent.



    Merci à  tous.
  • epetit91epetit91 Membre
    juin 2012 modifié #9
    Bonsoir uocram,



    En complément de l'aide que tu m'as apportée dans mon problème de lecture écriture de fichier, peux-tu me dire comment fait-on pour écrire des données à  la suite d'un fichier ?



    Dans ton exemple

    <br />
    [outputString writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&amp;error]<br />
    


    ce code crée le fichier "path" et y écrit "outputstring".



    Au cours du déroulement du programme, je veux continuer à  écrire des string dans ce fichier.

    Comment dois-je faire pour écrire des string à  la suite du fichier "path" ?



    Question complémentaire : à  l'issue de la ligne suivante
    <br />
    [outputString writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&amp;error]<br />
    




    le fichier est-il fermé automatiquement ou doit-on écrire une instruction particulière ?



    La gestion des fichiers est vraiment ma bête noire en Cocoa !!!!

    Merci encore pour ton aide.

    Cordialement
  • AliGatorAliGator Membre, Modérateur
    En fait, [font=courier new,courier,monospace]writeToFile:atomically:encoding:error:[/font] est une méthode de commodité, qui va créer un objet représentant le fichier, et écrire dedans les octets correspondants à  ta chaà®ne.

    L'inconvénient de cette méthode c'est que comme c'est une méthode de commodité, son but est de réduire la quantité de code à  écrire pour juste écrire une chaà®ne dans un fichier, donc elle n'expose pas spécialement toutes les subtilités et possibilités que tu pourrais vouloir. Si tu veux un peu plus de maà®trise dans l'écriture des données, écrire des données binaires, choisir les attributs du fichier écrit (droits d'accès, flags, etc), ou écrire à  la fin d'un fichier plutôt que d'écraser un existant, tu as des classes un peu plus poussées pour faire cela



    Pour écrire dans un fichier, tu as plusieurs solutions, globalement équivalentes :
    • La méthode de commodité "writeToFile:atomically:...", très simple à  utiliser, mais offrant peu de configuration, et du coup entre autre n'offrant pas la possibilité de rajouter une chaà®ne à  la fin d'un fichier et ne permettant que d'écraser un fichier existant
    • Tu peux imaginer ruser, en relisant le contenu de ton fichier, le mettre dans une NSString, concaténer cette NSString et la chaà®ne que tu veux rajouter à  la suite, puis tout réécrire sur le fichier (en écrasant l'ancien). Mais bon c'est un peu violent, surtout si ton fichier grossit de façon conséquente, tout réécrire à  chaque fois semble assez rude, donc pas une si bonne idée.
    • Tu peux plutôt regarder du côté de NSOutputStream : Tu crées un NSOutputStream avec "[font=Courier, Consolas, monospace]+ (id)outputStreamToFileAtPath:([/font]NSString[font=Courier, Consolas, monospace] *)[/font]path[font=Courier, Consolas, monospace] append:(BOOL)[/font]shouldAppend" (et tu vois là  que tu peux demander à  écrire à  la fin d'un fichier existant ou écraser ce dernier, au choix), puis tu ouvres le flux/le fichier avec la méthode "open", tu écris tes données avec "-write:maxLength:", et tu fermes le fichier avec "close".
    • Tu as aussi la classe NSFileHandle qui te permet également de manipuler des fichiers. Pour l'utiliser, tu crées un NSFileHandle avec "[font=Courier, Consolas, monospace]+ (id)fileHandleForWritingAtPath:([/font]NSString[font=Courier, Consolas, monospace] *)[/font]path", tu te places à  la fin du fichier avec "[font=Courier, Consolas, monospace]-seekToEndOfFile[/font]", puis tu écris tes données avec "[font=Courier, Consolas, monospace]- (void)writeData:([/font]NSData[font=Courier, Consolas, monospace] *)[/font]data" (bien sûr il te faudra donc convertir ta NSString à  écrire en NSData, en choisissant un encodage, typiquement UTF8, donc typiquement avec la méthode "[font=Courier, Consolas, monospace][outputString dataUsingEncoding:NSUTF8StringEncoding][/font]"


    Cela te donne une idée des différentes possibilités, chacune ayant des avantages et inconvénients différents. Perso je te conseillerai l'approche NSFileHandle, qui me semble la plus simple et explicite.
  • Merci beaucoup Ali pour ces explications simples mais très explicites qui me donnent une bonne idée des possibilités.

    Je pense que je vais utiliser la classe NSFileHandle.

    Merci encore
Connectez-vous ou Inscrivez-vous pour répondre.