2 votes

Comment écrire dans un fichier, de la fin au début, en C++ ?

J'ai une fonction qui calcule le résultat dont j'ai besoin à la volée (le résultat final étant des fichiers texte de ~50 Mo contenant uniquement des caractères), mais dans l'ordre inverse.

Pour illustrer : Ma fonction calculera "5, 4, 3, 2, 1, ...", mais j'ai besoin que "1, 2, 3, 4, 5" soit écrit dans un fichier.

Je voudrais l'écrire dans un fichier de sortie, à la volée, de bout en bout.

Actuellement, je mets en mémoire tampon, j'inverse, et j'écris dans un fichier avec std::ofstream::binary mais j'ai besoin de réduire le temps et surtout l'espace nécessaires.

Quel est le moyen le plus efficace de le faire ?

Merci.

Edit : la taille de la sortie est connue.

0voto

Ihor Drachuk Points 1166

En fait, écrire des fichiers de la fin au début est une solution inefficace, car vous perdez du temps sur la pré-affectation et la recherche de fichiers. Il est préférable d'écrire le tableau de la fin au début du fichier.

Je ne sais pas exactement comment est écrit votre programme, donc ma réponse pourrait ne pas être aussi précise que vous le souhaitez, mais je suppose que cela pourrait être fait quelque chose comme ça :

#include <iostream>
#include <vector>
#include <ostream>
#include <fstream>

// Variant 1
void writeMyData(const std::vector<int>& data, std::ofstream& stream)
{
    for (auto it = data.rbegin(); it != data.rend(); it++)
        stream.write((const char*)&*it, sizeof(int));
}

// Variant 2
void writeMyData2(const int* data, int length, std::ofstream& stream)
{
    for (int i = length - 1; i >= 0; i--)
        stream.write((const char*)(data + i), sizeof(int));
}

int main()
{
    std::vector<int> yourBuffer = {5, 4, 3, 2, 1};
    std::ofstream file;
    file.open ("data.bin", std::ios::binary);

    // Write: 1, 2, 3, 4, 5
    // Variant 1
    writeMyData(yourBuffer, file);

    // Variant 2
    //writeMyData2(yourBuffer.data(), yourBuffer.size(), file); 

    file.close();
    return 0;
}

Ainsi, vous pouvez utiliser des itérateurs inversés ( rbegin , rend au lieu de begin , end ) ou simplement itérer la boucle dans l'ordre inverse.

Mise à jour : Ou vous pouvez inverser vos données dans la RAM en place, et ensuite écrire toutes les données en une seule fois. C'est probablement la méthode la plus efficace.

std::reverse(std::begin(yourBuffer), std::end(yourBuffer));
stream.write((const char*)yourBuffer.data(), sizeof(int) * yourBuffer.size());

Soyez attentif aux sizeof(int) - vous avez probablement char ou d'un autre type.

0voto

Armin Montigny Points 7869

Je comprends vos exigences comme ça :

  • Écrire des données sous forme binaire (bien que vous parliez de fichiers texte quelque part).
  • Vous voulez stocker des caractères simples
  • Vous connaissez à l'avance le nombre de caractères à écrire
  • Et ensuite, écrivez le premier élément à la fin, puis un avant et ainsi de suite.

Si vous ne voulez vraiment pas utiliser de tampons, alors vous devez utiliser seekp . Mais dès à présent, un indice : cette solution sera très lente.

Bref, comment faire ? Alors :

  • Ouvrez d'abord un fichier de sortie et vérifiez s'il peut être ouvert.
  • Calculer le décalage de la position du dernier caractère dans le fichier de sortie.
  • Cherchez à cette position et écrivez
  • Décalage de la décrue

La recherche et l'écriture ressembleront à ceci

fileStream.seekp(offset--).put(testData[index]);

Comme je ne dispose pas de votre fonction de calcul, j'ai créé des données factices. Vous devez les adapter.

Voir l'extrait d'exemple suivant :

#include <iostream>
#include <fstream>
#include <array>
#include <numeric>

// The known size of test data
constexpr size_t OutputSize = 50'000U;
// Some simple test data
static std::array<char, OutputSize> testData{};

int main() {

    // You will calculate the data in a different part of your code
    // I jsut fill the array with some data
    std::iota(testData.begin(), testData.end(), 0);

    // Open the file and check, if it could be opened.
    if (std::ofstream fileStream{ "r:\\test.bin", std::ofstream::binary }; fileStream) {

        // Caculate position offset of last element
        size_t offset{ (OutputSize - 1)};

        // Calculate and write data
        for (size_t index{}; index < OutputSize; ++index) {

            // Your claculation here
            // . . .

            // Seek and write data
            fileStream.seekp(offset--).put(testData[index]);
        }
    }
    return 0;
}

Encore une fois. La recherche est très lente.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X