Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C: fwrite/fread

Sivun loppuun

mauriasp [07.07.2008 10:21:27]

#

Yritän kirjoittaa binääritiedostoon tietyn verran ykkösiä. (eli alustaisin yksittäisillä ykkösillä tiedoston) Miten tämä tapahtuu? Sitten yritän lukea tuon tiedoston merkkijonoksi. Miten tämä tapahtuu?

Olen fwrite/fread-aiheisia tekstejä selannut mutta enpä vain ole saanut tätä hommaa toimimaan. Tulosteena on aivan ihmeellisiä arvoja. Lieneekö sitten väärät määrittelyt jossakin...

Mutta olisi hienoa jos jonkun esimerkin voisin saada. Siitä se sitten avautuisi.

Kiitos.

PS. niin ja kielenä C

Gaxx [07.07.2008 10:37:49]

#

const int LUKUJEN_MAARA = 10;
char luku = 1; // kirjoitettava luku

FILE* file = fopen("tiedosto.dat", "wb"); // 'b' == "binääri"
fwrite(luku, sizeof(char), LUKUJEN_MAARA, file);
fclose(file);

Toivottavasti selkis :)

Edit: Tai sit jos tarkotit '1':llä, eli asciina 49, lukuna täytyy olla tietenkin 49.

char luku = 49; tai char luku = '1';

mauriasp [07.07.2008 10:53:33]

#

Mites kun tuota kääntää nii alkaa valitus: passing arg 1 of `fwrite' makes pointer from integer without a cast.

Antti Laaksonen [07.07.2008 10:53:55]

#

Kysymyksesi voi nyt tulkita monella tavalla.

Vaihtoehto 1: tiedosto on täynnä ykköstavuja

bitit 00000001 00000001 00000001 00000001
tavut        1        1        1        1

Vaihtoehto 2: tiedosto on täynnä ykkösmerkkejä

bitit 00110001 00110001 00110001 00110001
tavut       49       49       49       49

(ASCII-järjestelmässä merkin '1' koodi on 49.)

Vaihtoehto 3: tiedosto on täynnä ykkösbittejä

bitit 11111111 11111111 11111111 11111111
tavut      255      255      255      255

Mitä näistä vaihtoehdoista tarkoitat? Entä mitä merkkijonoon pitäisi ilmestyä?

mauriasp [07.07.2008 10:55:27]

#

elikkä juuri tuo ensimmäinen vaihtoehto oli se mitä haen.
Eli pitäisi kirjoittaa tiedostoon esim. 500 ykköstä ja hakea ne merkkijonoksi, joka näyttää 500 ykköstä: 1111111111......

hunajavohveli [07.07.2008 11:08:49]

#

Miksei ykkösiä voisi tallentaa suoraan ASCII:na? ASCII:ksi ne pitää joka tapauksessa muuttaa, kun niistä tehdään merkkijono. Tarvitsetko vain 500 ykkösen merkkijonon, vai onko tiedostolla jokin muukin tarkoitus?

mauriasp [07.07.2008 11:13:54]

#

hunajavohveli kirjoitti:

Miksei ykkösiä voisi tallentaa suoraan ASCII:na? ASCII:ksi ne pitää joka tapauksessa muuttaa, kun niistä tehdään merkkijono. Tarvitsetko vain 500 ykkösen merkkijonon, vai onko tiedostolla jokin muukin tarkoitus?

Binääritiedostoa pitäisi käyttää juuri siksi, että niitä lukuja on oikeasti niin tuhoton määrä...

Antti Laaksonen [07.07.2008 11:14:30]

#

Tuossa on esimerkki:

#include <stdio.h>
#include <string.h>

char data[500+1];

int main(void) {
    FILE *tied;
    /* ykkösten tallennus tiedostoon */
    memset(data, 1, 500);
    tied = fopen("ykkoset.dat", "wb");
    fwrite(data, sizeof(char), 500, tied);
    fclose(tied);
    /* ykkösten lataus tiedostosta */
    tied = fopen("ykkoset.dat", "rb");
    fread(data, sizeof(char), 500, tied);
    fclose(tied);
    /* ykkösten tulostus */
    printf("%s\n", data);
    return 0;
}

Ohjelma ei kylläkään tulosta 500 ykköstä vaan 500 nauravaa naamaa tai miten merkki 1 esitetäänkin merkistössä. Mutta jos tallennat tiedostoon 500 kertaa merkin 49, ohjelma tulostaa 500 ykköstä.

Ohjelman nopeus pysyy samana, tallennettiinpa tiedostoon 500 merkkiä 1 tai 500 merkkiä 49. Eli "ASCII-tiedoston" käyttö ei mitenkään tarkoita, että ohjelmasta tulisi hidas.

hunajavohveli [07.07.2008 11:20:39]

#

mauriasp kirjoitti:

Binääritiedostoa pitäisi käyttää juuri siksi, että niitä lukuja on oikeasti niin tuhoton määrä...

Merkkijonon voi kyllä generoida ilman tiedostoakin tarvitsematta kirjoittaa kaikkia ykkösiä koodiin.

#include "string.h"

...

char merkkijono[500];
memset(merkkijono, '1', 500);    // Kopioidaan merkkijonoon 500 ykköstä

Edit: Vielä tosin herää kysymys, mihin tällaista merkkijonoa tarvitset.

Blaze [07.07.2008 11:22:03]

#

mauriasp kirjoitti:

lukuja on oikeasti niin tuhoton määrä...

Mistä lähtien 500 (tavua!) on ollu paljo?

mauriasp [07.07.2008 11:28:17]

#

Blaze kirjoitti:

mauriasp kirjoitti:

lukuja on oikeasti niin tuhoton määrä...

Mistä lähtien 500 (tavua!) on ollu paljo?

Heh. Niin tarkoitan siis että tuo 500 oli vain esimerkki. Ei siis se oikea tilanne...

Metabolix [07.07.2008 12:23:34]

#

Gaxx kirjoitti:

fwrite(luku, sizeof(char), LUKUJEN_MAARA, file);

Ei, ei toimi näin. Ei fwrite toista puskuria silmukassa vaan kirjoittaa sen yhden kerran. Parametrina pitää siis antaa juuri puskurin koko.

Yhden merkin voi tulostaa fputc-funktiolla, ja tätä voi käyttää silmukassa:

for (i = 0; i < haluttu_koko; ++i) {
  fputc('1', tiedosto);
  /* Tai (255, tiedosto), jos ihan oikeasti haluat ykkösbittejä */
}

Vastaavasti yhden merkin voi lukea fgetc-funktiolla:

/* Luetaan (fgetc), tallennetaan tulos muuttujaan (i) ja verrataan tulosta vakioon EOF eli end-of-file */
while ((i = fgetc(tiedosto)) != EOF) {
  /* Tiedosto ei loppunut, joten tulostetaan merkki ruudulle ja jatketaan lukemista */
  putchar(i);
}

Myös Antin esimerkki on oikein hyvä. Siinä siis memset-funktiolla laitetaan puskuriin valmiiksi monta merkkiä tulostettavaksi.

En saa vieläkään tekstistäsi selville, missä muodossa oikeasti haluat tallentaa datasi. Kerrataanpa nyt vielä. Bitti on ykkönen tai nolla, bittejä on tavussa (merkissä) kahdeksan. Erilaisia tavuja taas on tämän perusteella 256, ja kymmenen näistä esittää numeromerkkejä. Kun luku tulostetaan tekstinä, tilankäytön hyötysuhde on 10/256. Luvusta "123456" tulee tiedostoon tavut 47, 48, 49, 50, 51, 52 ja lopetusmerkki, joka täytyy tulostaa, jotta peräkkäiset luvut voidaan erottaa toisistaan. Sen sijaan binäärimuodossa lopputulos on 64, 226, 1, 0.

mauriasp [07.07.2008 13:21:05]

#

Joo kiitoksia avusta. Ongelma nyt taisi ratketa tuossa. Jatkokysymyksenä heitän vielä tämän: Miten korvataan tiedostosta merkki jollakin toisella merkillä siten, että muihin merkkeihin ei kosketa?

Metabolix [07.07.2008 13:47:28]

#

/* "r+": Luku ja kirjoitus, ei tyhjennystä */
f = fopen(nimi, "r+");
/* Oikeaan kohti siirtyminen tapahtuu fseek-funktiolla */
fseek(f, kohta, SEEK_SET);

Pekka Karjalainen [07.07.2008 13:54:13]

#

Tässä on esimerkki tiedoston päivittämisestä fseekin avulla.

#include <stdio.h>
#include <stdlib.h>

int main (void) {
  FILE *datafile;
  datafile = fopen ("testi.txt", "r+"); /* r+ on update-moodi */
  if (datafile == NULL) {
    printf ("Ohjelman ketaroiden tila: ojossa."
            " Syy: tiedosto ei auennut.\n");
    exit (1);
  }
  fseek (datafile, 20, SEEK_SET); /* ks. muut optiot manuaalista */
  fputs ("mesta", datafile);
  fclose (datafile);
  return EXIT_SUCCESS;
}

Esimerkkiajo. Tekstitiedoston tein itse valmiiksi ja cat-komento tulostaa tiedoston sisällön päätteelle. Prompti on % ja ./a.out on suorittavan tiedoston nimi (kääntäjä antaa sen oletuksena, jos ei itse jaksa keksiä nimeä).

% cat testi.txt
Ohjelmointiputka on kumma paikka.
% ./a.out
% cat testi.txt
Ohjelmointiputka on mesta paikka.

Se siis muutti tuon yhden sanan, kuten sorsaa lukemalla varmasti jo näki.

mauriasp [07.07.2008 14:00:48]

#

Kiitoksia kaikille avusta. Taas vasta-alkaja oppi vähän lisää..


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta