Wykorzystanie fseek i ftell w pliku binarnym

0

Witam. Otóż nie mogę dojść do tego dlaczego program nie zapisuje danych w odpowiednim miejscu. W skrócie, mam zapisanych do pliku binarnego 10 liczb typu double z tablicy wcześniej zdefiniowanej. Następnie muszę zamienić pierwszy i ostatni wyraz w pliku używając funkcji fseek oraz ftell.
Jeżeli chodzi o używanie fseek dla wczytywania argumentów to działa on jak należy. Ustawiam znacznik na początek pobieram 1 wyraz , tak samo ustawiam znacznik na przedostatni wyraz i pobieram ostatni. To działa. Następnie kiedy przechodzę znacznikiem gdziekolwiek w pliku i chcę zapisać tam pobrany wyraz fseek nie działa, cały czas zamienia tylko początkowy wyraz mimo że ustawiam znacznik na ostatni

Jeżeli ktoś ogarnia C to miałbym jeszcze parę pytań co do kilku zadań. Jeśli masz chwilę i mógłbyś/mogłabyś pomóc to proszę o wiadomość PW .
Z góry dziękuję !

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

int main()
{
	double wyraz1;
	double wyraz2;
	double tab[10]={12.0,15.0,17.0,21.0,15.5,16.25,17.11,19.22,22.22,99.97};
	double tab2[10];
	long odstep=sizeof(tab[0]);
	printf("%d \n",odstep);
	int i=0;
	FILE *p;
	p=fopen("DANE.BIN","w");
	if(p==NULL)
		printf("Pliczek sie nie otworzyl");
	else
	{
		for(i=0;i<20;i++)
		{
			fwrite(tab,sizeof(tab),1,p);	
		}

	}
	fclose(p);
	p=fopen("DANE.BIN","ab+");
	while(!feof(p))
	{
		fread(tab2,sizeof(tab2),1,p);
	}
	fclose(p);
	for(i=0;i<10;i++)
		printf("%.2f ",tab2[i]);
	p=fopen("DANE.BIN","a+b");
		fseek(p,0,SEEK_SET);
		fread(&wyraz1,sizeof(double),1,p);
		printf("%.2f",wyraz1);
		fseek(p,-odstep,SEEK_END);
		fread(&wyraz2,sizeof(double),1,p);
		printf("%.2f",wyraz2);
		fseek(p,0,SEEK_SET);
		fwrite(&wyraz2,sizeof(double),1,p);
		fseek(p,-odstep,SEEK_END);
		fwrite(&wyraz1,sizeof(double),1,p);
		fclose(p);
		printf("\n------------------------------------------------------\n");
		p=fopen("DANE.BIN","r");
		while(!feof(p))
	{
		fread(tab2,sizeof(tab2),1,p);
	}
	fclose(p);
		for(i=0;i<10;i++)
		printf("%.2f ",tab2[i]);
	return 0;
}
1
dodo070 napisał(a):

mam zapisanych do pliku binarnego 10 liczb typu double z tablicy wcześniej zdefiniowanej.

Nie. Masz zapisane 200 liczb (Dwadzieścia 10-elementowych tablic).

for(i=0;i<20;i++)
		{
			fwrite(tab,sizeof(tab),1,p);	
		}

Zajrzyj w kod i zobacz w które miejsca tak naprawdę zapisujesz i którą tablicę wypisujesz.

Edit:
Poza tym jeśli chcesz tylko podmieniać liczby to powinieneś otwierać plik r+b/rb+. (link)

1
  1. Sugeruję, żebyś plik otwierał w trybie binarnym. Pod Windows to może mieć znaczenie
  2. Bardzo nie lubię oglądać w kodzie takich konstrukcji:
    if(p==NULL)
        printf("Pliczek sie nie otworzyl");
    else
    {
        for(i=0;i<20;i++)
        {
            fwrite(tab,sizeof(tab),1,p);    
        }

    }

Zamiast tego możesz zrobić:

    if(p==NULL) {
        printf("Pliczek sie nie otworzyl");
        return 1; // wartość różna od zera zwrócona z funkcji main zazwyczaj sygnalizuje błędne zakończenie działania programu
    }

    // tu else nie jest potrzebny, bo dla p==NULL program zakończy działanie
    for(i=0;i<20;i++)
    {
        fwrite(tab,sizeof(tab),1,p);    
    }
  1. Nie przyzwyczajaj się do używania sizeof(tab). To działa tylko tam gdzie nie jest potrzebne. Niezależnie od tego - uwaga @tajny_agent jest jak najbardziej słuszna

  2. Czytanie całej tablicy jednym fread jako jednego elementu o rozmiarze 10*sizeof(double) jest potencjalnie ryzykowne - nie musi się udać, a zwrócona wartość będzie wtedy trudna w interpretacji:

$ hexdump -C plik.txt 
00000000  41 42 43 44 0a                                    |ABCD.|
#include <stdio.h>
  
int main()
{
  char buf[100];
  int n;

  FILE *f = fopen ("plik.txt", "r");
  n = fread (buf, 100, 1, f);
  printf("n=%d\n", n);
  fseek (f, 0, SEEK_SET);
  n = fread (buf, 1, 100, f);
  printf("n=%d\n", n);

  return 0;
}
$ ./a.out 
n=0
n=5

Bezpieczniej jest zapisywać/wczytywać 10 wartości, gdzie każda jest rozmiaru sizeof(double)

// ŹLE: 
double tab[10];
...
fwrite(tab,sizeof(tab),1,p); 

// LEPIEJ
#define NELEM 10

double tab[NELEM];
fwrite (tab, sizeof( tab[0] ), NELEM, p); 
0

@Bartłomiej Golenko @tajny_agent: Dzięki wielkie za sprawdzenie !
Niestety nie udało mi się naprawić problemu. Rozumiem to tak :


	else
	{
			fwrite(tab,sizeof(double),10,p);	
          }

Wpisuje pliku 10 elementów z tablicy , każdy o rozmiarze double.

p=fopen("DANE.BIN","ab+"); 
		fread(tab2,sizeof(double),10,p);  --> wczytują z pliku to tab2  te 10 elementów.

	fclose(p);
	for(i=0;i<10;i++)
		printf("%.2f ",tab2[i]); --> wyświetlam sobie wszystkie elementy tablicy, tak dla sprawdzenia czy wpisało do pliku.
		p=fopen("DANE.BIN","a+b");
		fseek(p,0,SEEK_SET); --> ustawiam znacznik na początku 
		fread(&wyraz1,sizeof(double),1,p); -->wczytuję 1 napotkany wyraz o rozmiarze double do zmiennej wyraz1
		printf("%.2f",wyraz1); --> wyświetlam to dla sprawdzenia
		fseek(p,-odstep,SEEK_END); --> Ustawiam znacznik na przedostatnim elemencie (od końca odejmuje 1 raz rozmiar double)
		fread(&wyraz2,sizeof(double),1,p); -->  do zmiennej wyraz 2 zapisuję ostatni wyraz
		printf("%.2f",wyraz2); --> wyświetlam dla sprawdzenia   (wyraz1 i wyraz2 mają takie wartości jakie chciałem czyli ostatnią i pierwszą)
		fseek(p,0,SEEK_SET); --> ustawiam znacznik na sam początek
		fwrite(&wyraz2,sizeof(double),1,p); --> nadpisuję na początku pliku wyraz 2
		fseek(p,-odstep,SEEK_END); --> przechodzę wskaźnikiem na przedostaną pozycję
		fwrite(&wyraz1,sizeof(double),1,p); -->nadpisuje ostatnią pozycję zmienną wyraz1
		fclose(p);
		printf("\n------------------------------------------------------\n");
		p=fopen("DANE.BIN","r");
		while(!feof(p))
	{
		fread(tab2,sizeof(double),10,p); -->wczytuję dane z pliku do tablicy 
	}

3

Podrzuciłem Ci linka z wyjaśnieniem r+, w+, a+:

r+ will open a file for reading and writing. It will fail if the file does not exist. fseek can be used to read and write anywhere in the file.

w+ will open a file for reading and writing. It will create the file if the file does not exist, and destroy and recreate the file if the file does exist. fseek can be used to read anywhere in the file.

a+ will open a file for reading and writing. It will create the file if the file does not exist. fseek can be used to read anywhere in the file, but writes will always append to the end of the file regardless of any calls to fseek.

Jeśli otwierasz plik w trybie a+ to bez względu na fseek zapis jest dokonywany ZAWSZE na końcu pliku.
Czyli jeśli masz w pliku 10 liczb, otworzysz plik a+ i zapiszesz dwie liczby to w pliku będziesz miał 12 liczb, a te dwie zawsze będą na końcu.

0

@tajny_agent: Dziękuję bardzo za odpowiedź. Program działa.

1 użytkowników online, w tym zalogowanych: 0, gości: 1