2012-08-02 2 views
0

간단한 테스트 응용 프로그램을 만들었습니다. 목적은 텍스트 파일을 읽거나 쓰는 것입니다. "Firmware :"문자열을 찾고 있습니다. 아이디어는 장치가 패키지를 전송하여 저장 한 다음 활성화하는 것입니다. 해당 패키지의 이름 (예 : Update1)을 저장하고 싶습니다. 쿼리를 통해 패키지 이름을 다시 가져옵니다 (파일에서 읽기).C++ : 문자열을 대체하는 파일 검색 및 쓰기

문제 1 : 파일에 쓰지 않는 것 같습니다. 문제점 2 : 파일에 쓸 때 "Firmware : pkgName"줄이있는 경우 pkgName을 새 패키지 이름으로 바꾸려면 어떻게해야합니까?

이 프로그램은 실행되고 컴파일되므로 IDE 또는 텍스트 편집기에서 자유롭게 사용할 수 있습니다. 원하는대로 할 수 없습니다. 읽으려는 샘플 파일로 log.txt를 사용하고 있습니다. 이 작업을 수행하는보다 간단한 방법이있을 것입니다. 나는이 일을 얼마 동안하고 있었고 난 어려움에 빠졌습니다.

도움 주셔서 감사합니다.

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

using namespace std; 

int writeFile(string filename, string pkgName); 
int readFile(string filename); 

int main(void) { 
    string filename = "log.txt", userInput, pkgName; 
    system("touch log.txt"); 

    while (true) { 
     cout << "Write or Read?\n>>>"; 
     cin >> userInput; 

     if (userInput == "Write") { 
      cout << "What's your package name?\n>>>"; 
      cin >> pkgName; 
      writeFile(filename, pkgName); 
     } else if (userInput == "Read") { 
      readFile(filename); 
     } else { 
      cout << "Invalid Input"; 
     } 
    } 
} 

int writeFile(string filename, string pkgName) { 
    bool found, exists = true; 
    string line, word; 
    fstream firmwareFile; 
    int pos, size, num = 1; 
    firmwareFile.open(filename.c_str(), ios::in | ios::out | ios::app); 
    //firmwareFile << "This is a test."; 
    if (firmwareFile.is_open()) { 
     while (!found) { 
      getline(firmwareFile, line); 
      pos = line.find("Firmware: "); 
      if (pos != string::npos) { 
       //Found It 
       found = true; 
       exists = true; 
       size = line.size(); 
       word = line.substr(10, ((size - pos) + 10)); 
       cout << word << " is the old package name" << endl; 
       //TODO - Replace that with the new package name 
       firmwareFile.close(); 
      } else if (firmwareFile.eof()) { 
       //Doesn't Exist 
       found = true; 
       exists = false; 
       cout << "No last firmware package available.\n"; 
      } else { 
       //Still Looking 
       found = false; 
       cout << "Searching line #" << num << endl; 
      } 
      num++; 
      if (!exists) { 
       firmwareFile << endl << "Firmware: " << pkgName << endl; 
       cout << "Wrote package name to file\n" << endl; 
      } 
      firmwareFile.close(); 
     } 
    } else { 
     cout << "Unable to open file"; 
    } 
} 

int readFile(string filename) { 
    bool found; 
    string line, word; 
    fstream firmwareFile; 
    int pos, size, num = 1; 
    firmwareFile.open(filename.c_str(), ios::in | ios::out | ios::app); 
    if (firmwareFile.is_open()) { 
     while (!found) { 
      getline(firmwareFile, line); 
      pos = line.find("Firmware: "); 
      if (pos != string::npos) { 
       found = true; 
       size = line.size(); 
       word = line.substr(10, ((size - pos) + 10)); 
       cout << word << endl; 
      } else if (firmwareFile.eof()) { 
       found = true; 
       cout << "No last firmware package available.\n"; 
       firmwareFile << endl << "Firmware: "; 
      } else { 
       cout << "Searching line #" << num << endl; 
      } 
      num++; 
     } 
     firmwareFile.close(); 
    } else { 
     cout << "Unable to open file"; 
     firmwareFile.close(); 
    } 
    firmwareFile.close(); 
} 

가 여기 내 log.txt에 파일의 내용이다 : 음

You 
Think 
It's 
Here 
But 
It's 
Not 
So 
That 
Sucks 
Doesn't 
It 
? 
Firmware: Update1 
I 
Hope 
You 
Caught 
It 
! 
+1

임의의 위치에 쓰려면 이진 모드로 파일을 열어야합니다. 다른 옵션은 말의 벡터 벡터에서 파일을 읽고, 원하는 문자열을 대체하고, 새 파일을 작성하고, 이전 파일을 삭제하고, 새 파일의 이름을 이전 이름으로 바꿉니다. 지금은'ios :: app'로 스트림을 열고 있으므로 모든 쓰기 작업이 파일의 끝에 추가됩니다. – jrok

+0

내가 직면 한 유일한 문제는 구성 파일에있는 이전 파일을 삭제할 수 없으며 전체 파일을 복사해야한다는 것입니다. 내가 "간단하게"(아무것도 간단하지 않다, 나는 알고있다) 라인을 지우고 끝에 추가하거나 라인의 packageName만을 바꿀 수 없습니까? – Cr4cKeR

+0

아니요, 파일 가운데에서 데이터를 지울 수는 없으며 파일을 바꿀 수만 있습니다. 그리고 config 파일을 지우지는 않을 것입니다. 기본적으로 변경된 일부 데이터를 복사합니다. – jrok

답변

0

변경 :

std::ifstream cfg("log.txt"); 
std::ofstream tmp("log.tmp"); 
std::string line; 
std::string pkgName; 

while(std::getline(cfg, line)) { 
    if (line.find("Firmware:") != std::string::npos) { 
     line = "Firmware: " + pkgName; 
    } 
    tmp << line << '\n'; 
} 

하는 자, 이름 바꾸기와 파일을 삭제하면 특정 플랫폼이다. 휴대용 솔루션을 원한다면 Boost Filesystem 라이브러리를 살펴 보는 것이 좋습니다.

+0

나는 임베디드 리눅스 시스템을 사용하고 있으므로, 단지 'mv log.tmp log.txt'를 사용하고 그것을 덮어 쓸 것입니다. 감사! 그러면 변경된 파일을 복사하는 전체 과정이 수행됩니까? 내가 몇 가지 일을 복잡하게 끝내는 것처럼 보입니다! – Cr4cKeR

+0

일부 오류 검사, 특히 스트림이 열려 있는지 확인하고 쓰기 전에 '양호()'상태인지 확인하십시오. – jrok

+0

나는 한 가지를 제외하고는 모든 것이 작동한다. 복사는 계획대로 진행되지 않습니다. 파일에서 문자열을 찾은 다음 내용을 복사하지만 "Firmware :"인스턴스 뒤에 다음 줄 대신 파일의 시작 부분에서 시작하는 방법을 알아야합니다. fstream으로이 작업을 수행 할 수있는 방법이 있습니까? – Cr4cKeR

2

(제외한 모든 라인 포함 "펌웨어"간단하다). 첫 번째 질문은 함수 쓰기 파일에 변수 found이 있고 잠시 동안 테스트하면 while (!found) { ... }입니다. 문제는이 변수를 처음 테스트 할 때 어떤 값으로 설정하지 않았기 때문입니다. 거기에 정의되지 않은 동작이 있습니다. 나머지 코드를 살펴보면 do while 루프를 사용해야한다고 생각합니다. do { ... } while (!found); while 루프가 아닙니다. readFile에서도 같은 문제가있는 것처럼 보입니다.

두 번째 질문은 내가 두려워하는 나쁜 소식입니다. 정확히 같은 길이의 문자열로 바꾸지 않으면 파일의 문자열을 바꿀 수 없습니다. 디스크에 파일을 구성하는 방식의 한계에 불과합니다. 교체를 달성 할 수있는 유일한 방법은 전체 파일을 메모리로 읽어 들이고 메모리에서 교체 한 다음 전체 파일을 디스크에 다시 쓰는 것입니다.

2

@jrok가 문제 2에 대한 답변을했지만, 발견 된 코드가 초기화되지 않았기 때문에 매번 쓰지 않는 것으로 판단됩니다. 그러므로 정의되지 않았으므로 while 루프가 전혀 실행되지 않습니다. 발견 된 파일과 존재하는 파일을 모두 초기화해야합니다. bool found = false, exists = true;

+0

루프를 전환하고 부울을 초기화했으며 아직 논픽션 문제가 발생했습니다. 나는 ios :: app 플래그가 있고 eof가 될 때까지 읽었을 것으로 생각됩니다. 이 문제를 해결할 방법이 있습니까? 내가 찾는 라인이 없다면, 어떻게 끝까지 추가 할 수 있습니까? 나는 펌웨어를 옮겼습니다. 파일 ""펌웨어 : "<< pkgName; 몇 개의 다른 공백으로하지만 쓸 수는 없습니다. firmwareFile << "This is a test"행의 주석 처리를 제거하면 잘 작성됩니다. – Cr4cKeR

+0

'eof'가 true를 반환하면, 스트림은 에러 상태가되고 이후 쓰기 작업은 실패합니다. Yon은'ios :: clear()'를 사용하여 오류 플래그를 제거해야합니다. – jrok

0

파일의 내용을 바꿔야하고 (삭제하지 않고 다른 파일의 이름을 바꾸지 않으면) 전체 파일을 읽어야합니다. 메모리에있는 파일을 필요한대로 변경 한 다음 메모리 내 파일의 전체 내용을 디스크상의 파일에 기록하고 덮어 씁니다.

원본 파일을 삭제하는 것이 허용되면 이러한 변환을 수행하는 것이 훨씬 쉽습니다. 소스 파일을 읽고, 임시 파일을 열고, 파일에 쓰기 만하면됩니다. 즉석에서 필요한 모든 변경 작업을 수행하면됩니다. 원본 파일 처리가 끝나면 원본 파일을 삭제하고 새 파일의 이름을 원래 원본 파일과 동일한 이름으로 바꿉니다. 당신은 단지 해당 줄에 다른 파일을 작성하는 경우 당신은 일을 단순화 할 수