Zapisywanie do konkretnej lini w pliku tekstowym - fstream

0
void WriteLine(const std::string &name, std::string wline, int line)
{
    std::fstream fin(name.c_str());
    if(fin.is_open() == 1)
    {
        for(int i = 0; i <= line; i++)
        {
            if(i == line)fout << wline << std::endl;
        }
    }
    fin.close();
}

//struktura pliku
//qwerty
//acgd
//hfdghgf

Chciałbym po wywołaniu funkcji

WriteLine("C:\t.txt", "ZZZ", 2);

otrzymać

//struktura pliku
//qwerty
//ZZZ
//hfdghgf

Jednak nie wiem jak poruszać się po pliku.
Da ktoś jakieś wskazówki?

0

Jak mam przesunąć tak by zapisać np: wiersz niżej?

0

Już widziałem te strony i naprawdę nie wiem :/

używając

fout.seekp(24);

dostaje

sdfsdf sdf sdf

0

x - linia do której chcemy zapisać,

Jedziesz na koniec linii x-1, na początku string'a do zapisania dodajesz znak nowej linii. Zapisujesz.

0

A jeśli chciałbym przejść do siódmej linijki?
To miało by to tak wyglądać?
"/n/n/n/n/n/n/ntekst?"

0

a jak ustawie się w 6 wierszu?

0

Wiem tyle samo co przed założeniem tematu ale spróbuje coś pomyśleć.

0

Podpowiem jeszcze trochę. Pętla + zbieranie informacji ile znaków jest do ostatniego znaku końca linii + ustalenie pozycji kursora = rozwiązanie.

0

OK myśle że znalazłem rozwiązanie.
Napisałem sobie taką klase.

 
#include <string>
#include <vector>
#include <fstream>

class CFile
{
public:
    CFile();
    ~CFile();

    bool loadFile(std::string PathToFile);
    void saveFile();///konczy prace z plikiem

    std::string getLine(unsigned int numberLine);///otrzymujemy linie ktoranas interesuje
    void changeLine(std::string str,unsigned int numberLine);///zamienia linie podana w drugim argumencie na to co jest w strinu
private:

    std::fstream * HandleToFile;
    std::vector <std::string> linesOfTheFile;
    std::string m_PathToFile;
    bool wasChanged;

protected:

};
CFile::CFile()
{
    HandleToFile = new std::fstream;
    wasChanged = 0;
}
CFile::~CFile()
{
    delete HandleToFile;
}
bool CFile::loadFile(std::string PathToFile)
{
    m_PathToFile = PathToFile;
    HandleToFile->open( m_PathToFile.c_str(), std::ios::in | std::ios::out);///otwarcie z mozliwoscia odczytu i zapisu

    if(HandleToFile->good() == true)/// uzyskano dostep
    {
        while( HandleToFile->eof() == false ) /// sa jeszcze dane do odczytu
        {
            std::string tempstr;///tymczasowy string
            getline( *HandleToFile, tempstr );///wczytujemy caly wiersz do stringa

            linesOfTheFile.push_back(tempstr);///dokldamy stringa na koniec
        }
     HandleToFile->close();
    return 0;///sukces
    }
 return 1;///error
}
void CFile::saveFile()
{
    HandleToFile->open( m_PathToFile.c_str(), std::ios::trunc | std::ios::out);

    if(HandleToFile->good() == 1 && wasChanged == 1)
    {

      for( unsigned int i = 0; i < linesOfTheFile.size(); i++ )
      {
        ///tablica jest za kazdym razem wieksza przez to ze na koncu ostatniej lini dodawany jest zank konca lini
        /// rozwiazaniem jest sprawic by na koncu nie byl dodawany znak
         if( ( i+1 < linesOfTheFile.size() ) == false)///czy to ostatnia linia do zapisu
         {//tak
             *HandleToFile << linesOfTheFile[ i ];
         }
         else
        {//nie
          *HandleToFile << linesOfTheFile[ i ] << std::endl;
        }
      }
      HandleToFile->flush();
    }
    HandleToFile->close();
}
std::string CFile::getLine(unsigned int numberLine)
{
   return linesOfTheFile[numberLine];
}
void CFile::changeLine(std::string str,unsigned int numberLine)
{
    if(linesOfTheFile.size() < numberLine)
    {
        unsigned int j = numberLine+1-linesOfTheFile.size();
        for(unsigned int i = 0;i < j;i++)
        {
            linesOfTheFile.push_back("");///wstawianie pustej lini
        }
    }
    linesOfTheFile[numberLine] = str;
    wasChanged = 1;

}

Czy mógłby ktoś ocenić czy ten kod jest "znośny".

0

@spartanPAGE
@Satirev

Łatwo o wyciek pamięci - czy możecie mnie uświadomić gdzie ?
Ta wiedza może mi się przydać w przyszłości.

Kod głupi u podstaw - no cóż
"Jeśli coś jest głupie, ale działa, to nie jest głupie."
http://pl.wikiquote.org/wiki/Prawa_Murphy%27ego

Niepotrzebne zagnieżdżenia - w sensie ? za dużo if'ów ? czy coś serio pytam.

Tłuste metody można zapisać w 2/3 linijkach - proszę o przykład.


PS Jak by ktoś był tak dobry to może napisze kod lepszy od mojego i pokaże jak to powinno wyglądać np wczytywanie pliku - taka prośba.

0

Wycieki: http://ideone.com/09FrY5

#include <iostream>
using namespace std;

struct WhatHappendsHere{
	int foo;
	~WhatHappendsHere(){
		cout << "dtor: " << foo << endl;
	}
};

int main() {
	WhatHappendsHere a = {1};
	{
        WhatHappendsHere b = {2};
        b = a;
	}
	return 0;
}

Do reszty przepraszam, ale bez wina dzisiaj nie usiądę.

0

@spartanPAGE

Wybacz, może to środek nocy albo to że jestem za mało wtajemniczony w programowanie ale absolutnie nie rozumiem jak twój kod odnosi się do mojego.
Z cała pewnością to co napisałem można napisać prościej ale twój kod nic mi nie mówi.
Gdzie u mnie widzisz wyciek pamięci ?

0

@spartanPAGE

Czyli mam zamaist

fstream *HandleToFile

wstawić fstream HandleToFile

 ?
Używam przecież new i delete więc gdzie wyciek?
Wrzuciłem kod na ideone i nic nie pokazało oprócz:


> Sukces	time: 0 memory: 3232 signal:0
> 
> Sukces	time: 0 memory: 3276 signal:0
> 
> Sukces	time: 0 memory: 3276 signal:0


Czy to memory to ilość pamieci jaką zabiera program ? (Nie korzystałem za bardzo  tego serwisu)

http://ideone.com/cZzkhz
0

Stdout. W tym konkretnym scenariuszu jeden zaspób wisi w pamięci, drugi jest zwalniany podwójnie

Mówisz o :

@spartanPAGE

Czyli mam zamaist

fstream *HandleToFile

wstawić

fstream HandleToFile

?
Używam przecież new i delete więc gdzie wyciek?

Jak zrezygnuje ze wskaźnika to oczywiście wykasuje delete HandleToFile i nic nie będzie zwalnianie podwójnie

Mimo to moja klasa działa i dalej nie wiem jak ktoś może to napisać w 2/3 linijkach.

0

Wieczorem Ci to napisze

  • spartanPAGE
    Chciałbym się przypomnieć... :0
1

Prosz

#include <string>
#include <vector>
#include <fstream>
#include <string>

using Str = std::string;
using StrRef = Str &;
using CStrRef = const StrRef;

template<
	template<class, class> class ContainerT = std::vector,
	template<class> class AllocatorT = std::allocator
>
class FileHeldInMemory{
public:
	using LineType = Str;
	using Allocator = AllocatorT<LineType>;
	using Container = ContainerT<LineType, Allocator>;
public:
	void loadLinesFrom(CStrRef path){
		Str line;
		if(auto file = std::ifstream(path))
			while(getline(file, line))
				lines.push_back(line);
	}
	void saveTo(CStrRef path){
		if(auto file = std::ostream(path))
			for(const auto &element : lines)
				file << element << std::endl;
	}
	inline const LineType &lineAt(size_t id) const{
		return lines[id];
	}
	inline LineType &lineAt(size_t id){
		return const_cast<LineType&>(static_cast<const FileHeldInMemory*>(this)->lineAt(id));
	}
private:
	Container lines;
};
0

@spartanPAGE

Nie żebym coś wybrzydzał ale JAK TEGO UŻYĆ ?

template<
    template<class, class> class ContainerT = std::vector,
    template<class> class AllocatorT = std::allocator
>
  1. Nie wiem jak się zabrać za to wyżej - pierwszy raz widzę szablon w szablonie
    2 Szablony - czemu ich użyłeś.
0

W wydaniu, które ty potrzebujesz:

FileHeldInMemory<> file;
0

Ehhh... dalej nie wiem jak tego użyć
Nie żebym był troszkę bardzo niedouczony jak widzę ale

FileHeldInMemory<> file;

co i najważniejsze ILE wpisać do tego nawiasu.

Moje było prostsze.

0

Nic nie wpisuj, są zapewnione domyślne argumenty

0

Próbuje otworzyć za pomocą twojej klasy plik ale mam błędy.

int main()
{
  using path = std::string;
  path = "./abc.txt";///tu blad
  using pathRef = path &;
  FileHeldInMemory<> file;
  file.loadLinesFrom(pathRef);///tu blad
  return 0;
} 

== Build: Debug in spartanPage Otwieranie pliku (compiler: GNU GCC Compiler) ===

expected unqualified-id before '=' token|
expected primary-expression before ')' token|
0
using path = std::string

jest równoważne

typedef std::string path

To nie jest deklaracja zmiennej path. path jest inną nazwą na std::string. Jak dla mnie te using tutaj są niepotrzebne, używaj po prostu std::string i std::string&.

0

Czyli jak sprawić żeby zadziałało bo tą CUDNĄ klasą nie mogę nawet otworzyć pliku.

Nowy kod:

 int main()
{

  using m_CStrRef = const std::string &;
  std::string path = "./abc.txt";
  m_CStrRef pathToFile = path;
  FileHeldInMemory<> file;
  file.loadLinesFrom(pathToFile);
  return 0;
}

== Build: Debug in spartanPage Otwieranie pliku (compiler: GNU GCC Compiler) ===

error: no matching function for call to 'FileHeldInMemory<>::loadLinesFrom(const string&)'|
note: candidate is:|
note: void FileHeldInMemory<ContainerT, AllocatorT>::loadLinesFrom(CStrRef) [with ContainerT = std::vector; AllocatorT = std::allocator; CStrRef = std::basic_string<char>&; Str = std::basic_string<char>]|
note: no known conversion for argument 1 from 'const string {aka const std::basic_string<char>}' to 'CStrRef {aka std::basic_string<char>&}'|

0

Żeby się skompilowało, wystarczą 2 poprawki:

using m_CStrRef = const std::string &;

na

using m_CStrRef = std::string &;

oraz

if(auto file = std::ifstream(path))

na

if(auto&& file = std::ifstream(path))

Natomiast nie wiem jak będzie z działaniem :P

@spartanPAGE

using CStrRef = const StrRef;

nie tworzy aliasu na const string&.

1

@spartanPAGE
Ok przetestowałem te klasę i tak:

void loadLinesFrom(CStrRef path)

gdzie :

using Str = std::string;
using StrRef = Str &;
using CStrRef = const StrRef;

Czemu nie można:

 void loadLinesFrom(std::string path)

Sprawdziłem działa
Dzięki tej zmianie mozna od tego momentu używać funkcji nie tak:

  using m_CStrRef = std::string & ;
  std::string path = "./abc.txt";
  m_CStrRef pathToFile = path;
  FileHeldInMemory<> file;
  file.loadLinesFrom(pathToFile);

Tylko tak:

  std::string path = "./abc.txt";
  FileHeldInMemory<> file;
  file.loadLinesFrom(path);

lub:

  FileHeldInMemory<> file;
  file.loadLinesFrom("./abc.txt");

Odczytywanie lini pliku:

    inline const LineType &lineAt(size_t id) const{
        return lines[id];
    }
    inline LineType &lineAt(size_t id){
        return const_cast<LineType&>(static_cast<const FileHeldInMemory*>(this)->lineAt(id));
    }

gdzie:

using LineType = Str;
using Str = std::string;

Czemu są dwie funkcje nie wystarczy jedna moim zdaniem.
Nie mówiąc o tym czy takie cuda nie pojęte są potrzebne.

 return const_cast<LineType&>(static_cast<const FileHeldInMemory*>(this)->lineAt(id));

Brak możliwości zapisania (już nie mówię że dowolnej) linii do pliku tekstowego - chyba ze czegoś nie widzę bynajmniej nie dostrzegam.

Przy okazji znalazłem potencjalnego buga u ciebie i u mnie :

Wczytujemy plik abc.txt
Jego zawartośc to:

tekst
testowy

Uzywamy funkcji

    inline const LineType &lineAt(size_t id) const{
        return lines[id];
    }
    inline LineType &lineAt(size_t id){
        return const_cast<LineType&>(static_cast<const FileHeldInMemory*>(this)->lineAt(id));
    }

I teraz w jakiejś funkcji:

FileHeldInMemory<> file; 
std::string wynik = file.lineAt(0);//wynik tekst
std::string wynik = file.lineAt(1);//wynik testowy

std::string wynik = file.lineAt(2lubwiecej);// **wywali porgram**

Idziemy dalej

void saveTo(CStrRef path);

Po co funkcja zapisująca plik skoro nie zauważyłem żeby istniała funkcja modyfikująca plik czy linie tego pliku.

Ogólne odczucia i opinia i w ogóle w szczególe.(subiektywne)
Przez wszelkie udziwienia klase użyć cięej niż moją
Takie cuda zaciemniają "przekaz"

 using Str = std::string;
using StrRef = Str &;
using CStrRef = const StrRef;

template<
    template<class, class> class ContainerT = std::vector,
    template<class> class AllocatorT = std::allocator
>
class FileHeldInMemory{
public:
    using LineType = Str;
    using Allocator = AllocatorT<LineType>;
    using Container = ContainerT<LineType, Allocator>;
....
return const_cast<LineType&>(static_cast<const FileHeldInMemory*>(this)->lineAt(id));
.....
 if(auto file = std::ostream(path))
 for(const auto &element : lines)
....
if(auto&& file = std::ifstream(path))
0

Czego innego oczekujesz po vector::operator []? To nie bug, tylko twoja niezdolność do przeglądania dokumentacji - możesz użyć .at i wtedy będzie rzucalo wyjątkami.

0

Gdzie przekombinowałem wywołanie @spartanPAGE ?

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