2012-06-10 31 views
5

Tengo un programa en C++ que necesita devolver una línea que una palabra específica aparece en Por ejemplo, si mi archivo tiene el siguiente aspecto:Leer desde un punto específico en un archivo C++

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

y yo necesita imprimir la línea que tiene "con". Todo lo que obtiene el programa es el desplazamiento desde el principio del archivo (en este caso 24, ya que "con" tiene 24 caracteres desde el comienzo del archivo).

¿Cómo imprimo toda la línea "la luna con el", con solo el desplazamiento?

¡Muchas gracias!

+0

Busque el desplazamiento que tiene, y luego retroceda hasta encontrar una nueva línea. Luego lea hasta la próxima nueva línea. Fácil. –

+0

¿Hay alguna forma de leer toda una línea a la vez, sin leer de una línea nueva a la siguiente? – Meir

+1

Leer toda una línea a la vez * es * leer de una nueva línea a la siguiente. –

Respuesta

2

Una buena solución es leer el archivo desde el principio hasta la posición deseada (respuesta por @Chet Simpson). Si desea la optimización (por ejemplo, un archivo muy grande, posición en el medio, líneas típicas bastante cortas), puede leer el archivo al revés. Sin embargo, esto solo funciona con archivos abiertos en modo binario (cualquier archivo en plataformas unix; abre el archivo con el parámetro ios_base::binary en Windows).

El algoritmo es el siguiente:

  • Volver unos pocos bytes en el archivo
  • Leer los pocos bytes
  • Si hay una línea de fin de ahí, el resto es fácil
  • en caso contrario, repetir

Código (probado en 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; 
} 

Editar: En las plataformas de Windows-como, en los que al final de la línea está marcada por \r\n, ya que se debe utilizar el modo binario, la cadena de salida contendrá el carácter adicional \r (a menos que no hay fin-de- línea al final del archivo), que puede tirar.

0

Hay algunas funciones de cada uno de la operación fopen - abrir el archivo

fseek - buscar el archivo a la compensación deseada

fread - leer la cantidad de bytes que desea

fclose - cierre el archivo

3

Puede hacerlo leyendo cada línea individualmente y registrando la posición del archivo antes y después de la lectura. Entonces, es solo un simple control para ver si el desplazamiento de la palabra cae dentro de los límites de esa línea.

#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; 
} 
Cuestiones relacionadas