我正在寻找一个干净的c ++解决方案,在处理从ifstream读取的字符串后,读取和写入同一个文件。例如,这就是我的想法
std::ofstream ofs("test.txt", std::ios_base::app);
std::ifstream ifs("test.txt");
std::string inputLine;
bool skipLine = false;
if (ofs)
{
while (getline(ifs, inputLine))
{
skipLine = processLine(inputLine);
if (!skipLine)
ofs << inputLine << std::endl;
}
}
不幸的是,这不起作用。我打算读取行并决定“processLine()”函数天气我想写回行或跳过它。结果输出内容几乎是输入行的内容减去我要清除的某行
答案 0 :(得分:1)
我认为您最好的选择就是创建一个临时文件,该文件应该是您的输出文件。要解释为什么要这样做,请阅读您问题下方的评论。
这是一个很好的,干净的例子,工作正常:
#include <string>
#include <iostream>
#include <fstream>
#include <sys/stat.h>
/*
* @ FUNCTION: GenerateStr
* @ PARAMETER(s):
* [1st - in] const size_t in_Length = This parameter
* take in a size_t, which should be the length of the
* generated std::string.
* @ RETURN VALUE(s):
* This function should return the generated
* std::string, which was randomized during
* the generating process within this function.
*/
std::string GenerateStr( const size_t in_Length ) {
const std::string Elements =
"AaBcCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890$-_";
std::string FileName = "";
for( size_t Index = 0; Index != in_Length; ++ Index ) {
//# Add random characters from Elements.
FileName += Elements[ rand() % Elements.size() ];
}
return FileName;
};
/*
* @ FUNCTION: FileExists
* @ PARAMETER(s):
* [1st - in] const std::string &in_File = This parameter
* takes in a std::string, which should be the
* name of the file that will be searched for.
* @ RETURN VALUE(s):
* false = The file does not exists.
* true = The file does exists.
*/
bool FileExists( const std::string &in_FileName ) {
struct stat Buffer;
return ( stat( in_FileName.c_str(), &Buffer ) != -1 );
};
/*
* @ FUNCTION: GenerateTempFileName
* @ PARAMETER(s):
* [1st - in] const size_t in_Length = This parameter
* takes in a constant size_t value, which should be
* length of temporary file name (a.k.a the returned
* value).
* @ RETURN VALUE(s):
* This function will return a std::string, which
* should be a unique name for the temporary file.
*/
std::string GenerateTempFileName( const size_t in_Length ) {
std::string TempFileName = "";
while( FileExists( TempFileName = GenerateStr( in_Length ) + ".tmp" ) );
return TempFileName;
};
/*
* @ FUNCTION: OldFileToTempFile
* @ PARAMETER(s):
* [1st - in] const std::string &in_OldFileName = The
* name of the old file.
* [2nd - in] const std::string &in_TempFileName = The
* name of the temporary file.
* @ RETURN VALUE(s):
* 1 = An error has occured when attempting to rename the
* the old file to a temporary name.
* -1 = An error has occured when attempting to rename the
* temporary file to the original name of the old file,
* which is in_OldFileName.
* -2 = This is only a warning, although this function
* successfully renamed the temporary file to the original
* name of the old file, it failed to delete the old file.
* 0 = Successfully renamed the temporary file to
* in_OldFileName and deleted the old file.
*/
short OldFileToTempFile( const std::string &in_OldFileName,
const std::string &in_TempFileName )
{
//# Generate a temporary name for the old file.
const std::string OldFileTmpName = GenerateTempFileName( 15 );
//# Rename the old file to a temporary name. Why? So we can rename
// it back to its original name incase it failed to rename the
// temporary file.
if( std::rename( in_OldFileName.c_str(), OldFileTmpName.c_str() ) != 0 ) {
return 1;
}
//# If we successfully renamed the old file to a temporary name,
// we shall then attempt to rename the temporary file to the original
// name of the old file.
//# Attempt to rename the temporary file. If we fail, we shall rename
// the old file back to its original name.
if( std::rename( in_TempFileName.c_str(), in_OldFileName.c_str() ) != 0 ) {
std::rename( OldFileTmpName.c_str(), in_OldFileName.c_str() );
return -1;
}
//# Now if we successfully renamed the temporary file,
// we can go ahead and delete the old file. If failed,
// we shall return -2, which should only be a warning
// that we failed to delete the old file.
if( std::remove( OldFileTmpName.c_str() ) != 0 ) {
return -2;
}
return 0;
};
//# I wrote this function so it can instruct function ProcessFile to either skip
// the current line (in_Line) or to output the line to the temporary file. But
// mainly because, I did not know what your function processLine was actually
// doing.
bool ProcessLine( std::string &in_Line ) {
//# If in_Line is equal to "SkipThisLine", we shall return true,
// which means to skip the line. Else, it will return false,
// which simply means to no skip the line.
return ( in_Line == "SkipThisLine" );
};
/*
* @ FUNCTION: Example
* @ DESCRIPTION:
* This function is an example of how to read and write a file and also
* to answer the question above.
*/
bool Example() {
//# Attempt to open InFile (Test.txt).
std::ifstream InFile( "Test.txt" );
//# Return false if we are unable to open InFile.
if( ! InFile.is_open() ) {
std::cerr << "\nUnable to open file: Test.txt\n";
return false;
}
//# Generate a unqiue name for the temporary file.
const std::string TempFileName = GenerateTempFileName( 15 );
//# Create temporary file.
std::ofstream TempFile( TempFileName );
std::string InLine = "";
//# Begin processing each lines within InFile.
while( std::getline( InFile, InLine ) ) {
//# Process the line and check if we are suppose to skip it or not.
if( ! ProcessLine( InLine ) ) {
//# If we do not skip the line, we shall then write it to the
// temporary file (TempFile).
TempFile << InLine << std::endl;
}
}
//# Now that we are done with InFile, we can
// close both InFile and TempFile and continue
// to the next set of steps.
InFile.close();
TempFile.close();
//# Attempt to rename the temporary file to Test.txt.
short Error = OldFileToTempFile( "Test.txt", TempFileName );
//# Check if there are no error or if the error is -2.
// The -2 means that we successfully renamed the temporary
// file but we were unable to delete the old file.
if( Error == 0 || Error == -2 ) {
return true;
}
//# Failed to rename temporary file.
return false;
};
int main() {
if( Example() ) {
std::cout << "Success!" << std::endl;
} else { std::cout << "Failed!" << std::endl; }
::getchar();
return 0;
};
请阅读评论,他们真的很有帮助! :)
由于下面的@Michael Anderson的评论,我做了一些重要的更改,我们可以感谢他。
答案 1 :(得分:0)
这是一个使用您可以使用的随机访问方法的想法。它会留下最终的旧数据,根据您的应用程序,您可以忽略或删除。获得正确的取决于线条是否大小相同。但是,这应该删除您要跳过的行。
char buffer[10];
fstream fs("test.txt");
std::string inputLine;
bool skipLine = false;
long nextRead, nextWrite;
int skippedLines = 0;
if (fs)
{
while (!fs.eof())
{
if (!skipLine && skippedLines == 0)
nextWrite = fs.tellg();
getline(fs, inputLine);
nextRead = fs.tellg();
if (fs.eof()) break;
cout << inputLine << endl;
skipLine = processLine(inputLine);
if (!skipLine) {
fs.seekp(nextWrite);
fs << inputLine << std::endl;
if (skippedLines > 0) {
nextWrite = fs.tellp();
}
fs.seekg(nextRead);
if (fs.eof()) break;
} else {
fs.seekg(nextRead);
skippedLines++;
}
}
}