2012-06-10 9 views
5

Mam program w języku C++, która musi wrócić linię, która pojawia się konkretny wyraz w Na przykład, jeśli mój plik wygląda tak:Czytaj z określonego miejsca w pliku C++

the cow jumped over 
the moon with the 
green cheese in his mouth 

i I trzeba wydrukować linię, która ma "z". Cały program dostaje przesunięcie od początku pliku (w tym przypadku 24, ponieważ "z" ma 24 znaki od początku pliku).

Jak wydrukować całą linię "Księżyc za pomocą", tylko z przesunięciem?

Wielkie dzięki!

+0

Odszukaj przesunięcie, które masz, a następnie cofaj się, aż znajdziesz nowy znak. Następnie przeczytaj do następnego wpisu. Łatwo. –

+0

Czy istnieje sposób na odczytanie całej linii naraz, bez czytania od jednej linii do drugiej? – Meir

+1

Czytanie całej linii na raz * to * czytanie z jednego nowego wiersza do następnego. –

Odpowiedz

2

Dobrym rozwiązaniem jest czytanie pliku od początku aż do żądanej pozycji (Odpowiedź @Chet Simpson). Jeśli potrzebujesz optymalizacji (np. Bardzo duży plik, położenie gdzieś pośrodku, typowe linie raczej krótkie), możesz odczytać plik do tyłu. Działa to jednak tylko w przypadku plików otwartych w trybie binarnym (dowolny plik na platformach podobnych do systemu Unix, otwórz plik z parametrem ios_base::binary w systemie Windows).

Algorytm jest następujący:

  • cofnąć się kilka bajtów w pliku
  • Przeczytaj kilka bajtów
  • Jeśli jest koniec-linii tam, reszta jest prosta
  • W przeciwnym razie powtórzyć

kod (testowane na Windows):

std::string GetSurroundingLine(std::istream& f, std::istream::pos_type start_pos) 
{ 
    std::istream::pos_type prev_pos = start_pos; 
    std::istream::pos_type pos; 
    char buffer[40]; // typical line length, so typical iteration count is 1 
    std::istream::pos_type size = sizeof(buffer); 

    // Look for the beginning of the line that includes the given position 
    while (true) 
    { 
     // Move back 40 bytes from prev_pos 
     if (prev_pos < size) 
      pos = 0; 
     else 
      pos = prev_pos - size; 
     f.seekg(pos); 

     // Read 40 bytes 
     f.read(buffer, prev_pos - pos); 
     if (!f) 
      throw; 

     // Look for a newline byte, which terminates previous line 
     int eol_pos; 
     for (eol_pos = sizeof(buffer) - 1; eol_pos >= 0; --eol_pos) 
      if (buffer[eol_pos] == '\n') 
       break; 

     // If found newline or got to beginning of file - done looking 
     if (eol_pos >= 0 || pos == (std::istream::pos_type)0) 
     { 
      pos += eol_pos + 1; 
      break; 
     } 
    } 

    // Position the read pointer 
    f.seekg(pos); 

    // Read the line 
    std::string s; 
    std::getline(f, s, '\n'); 

    return s; 
} 

Edytuj: Na platformach podobnych do systemu Windows, gdzie koniec linii jest oznaczony przez \r\n, ponieważ musisz użyć trybu binarnego, ciąg wyjściowy będzie zawierał dodatkowy znak \r (chyba że nie ma końca). linia na końcu pliku), którą można wyrzucić.

0

Istnieją funkcje każdej operacji fopen - otwórz plik

fseek - poszukują plik do pożądanego przesunięcia

fread - odczyt ilości bajtów chcesz

fclose - zamknij plik

3

Możesz to zrobić, czytając każdą linię indywidualnie i rejestrując położenie pliku przed odczytem i po nim. Następnie wystarczy sprawdzić, czy przesunięcie słowa mieści się w granicach tej linii.

#include <iostream> 
#include <fstream> 
#include <string> 

std::string LineFromOffset(
    const std::string &filename, 
    std::istream::pos_type targetIndex) 
{ 
    std::ifstream input(filename); 

    // Save the start position of the first line. Should be zero of course. 
    std::istream::pos_type lineStartIndex = input.tellg(); 

    while(false == input.eof()) 
    { 
     std::string line; 

     std::getline(input, line); 

     // Get the end position of the line 
     std::istream::pos_type lineEndIndex = input.tellg(); 

     // If the index of the word we're looking for in the bounds of the 
     // line, return it 
     if(targetIndex >= lineStartIndex && targetIndex < lineEndIndex) 
     { 
      return line; 
     } 

     // The end of this line is the start of the next one. Set it 
     lineStartIndex = lineEndIndex; 
    } 

    // Need a better way to indicate failure 
    return ""; 
} 

void PrintLineTest() 
{ 
    std::string str = LineFromOffset("test.txt", 24); 

    std::cout << str; 
}