C++从文本文件中删除尾随新行

发布于 2024-09-26 17:21:29 字数 183 浏览 6 评论 0原文

C++ 中有没有办法从文本文件中删除/修剪尾随的新行?

例如

content content
content content
content content
<- this line in the text file is empty and needs to go ->

Is there a way in C++ to remove/trim a trailing new line from a text file?

For example

content content
content content
content content
<- this line in the text file is empty and needs to go ->

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

单身情人 2024-10-03 17:21:29

当然!一种方法是 将文件读取到 std:: string

#include <fstream>
#include <string>

 // Add this code inside your main() function
std::ifstream ifs("filename.txt");      
std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());

,然后使用此处描述的任何技术:

C++ 删除新的line from multiline string

然后您可以用新结果覆盖该文件。当然,这种方法在处理非常大的文件(比方说,2GB)时并不实用,但根据您原来的问题,这样的事情并不是一个限制。

这个线程也有关于检测新行的精彩材料。

Sure! One way to do it would be to read the file to a std::string

#include <fstream>
#include <string>

 // Add this code inside your main() function
std::ifstream ifs("filename.txt");      
std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());

and then use any of the techniques described here:

C++ Remove new line from multiline string

then you could overwrite the file with the new result. Of course, this approach ain't practical when dealing with very large files (let's say, 2GB) but such thing is not a constraint according to your original question.

This thread also has great material on detecting new lines.

摘星┃星的人 2024-10-03 17:21:29
ifstream fin("input.txt");
vector<string> vs;
string s;
while(getline(fin,s))
    vs.push_back(s);
fin.close();

ofstream fout("input.txt");
for(vector<string>::iterator it = vs.begin(); it != vs.end(); ++it)
{
    if(it != vs.begin())
        fout << '\n';
    fout << *it;
}
ifstream fin("input.txt");
vector<string> vs;
string s;
while(getline(fin,s))
    vs.push_back(s);
fin.close();

ofstream fout("input.txt");
for(vector<string>::iterator it = vs.begin(); it != vs.end(); ++it)
{
    if(it != vs.begin())
        fout << '\n';
    fout << *it;
}
我偏爱纯白色 2024-10-03 17:21:29

最有效的方法是查找文件末尾并将文件末尾指针向后移动。不幸的是,这不是可移植的,因为在 C 或 C++ 标准库中没有设置文件结束指针的标准方法。您需要使用特定于平台的函数,例如 Windows 上的 SetEndOfFileftruncate POSIX 上的 。例如:

void RemoveFinalNewline(const char *filename)
{
#if defined(_WIN32)
    HANDLE hFile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if(hFile == INVALID_HANDLE_VALUE)
        ;  // handle error

    LARGE_INTEGER fileSize;
    if(GetFileSizeEx(hFile, &fileSize) == 0)
        ;  // handle error
    if(fileSize.QuadPart < 2)
        ;  // this case is left as an exercise to the reader

    LARGE_INTEGER newFilePtr;
    newFilePtr.QuadPart = -2;
    if(SetFilePointerEx(hFile, &newFilePtr, NULL, FILE_END) == 0)
        ;  // handle error

    char lastTwoBytes[2];
    if(ReadFile(hFile, lastTwoBytes, 2, NULL, NULL) == 0)
        ;  // handle error

    if(lastTwoBytes[1] == '\n')
    {
        fileSize.QuadPart--;
        if(lastTwoBytes[0] == '\r')
            fileSize.QuadPart--;
        if(SetFilePointerEx(hFile, &fileSize, NULL, FILE_BEGIN) == 0)
            ;  // handle error
        if(SetEndOfFile(hFile) == 0)
            ;  // handle error
        // Success!
    }
    // else the file didn't end in a newline

    CloseHandle(hFile);  // and we're done
#else  // POSIX case; the non-Windows, non-POSIX case is left as an exercise
    int fd = open(filename, O_RDWR);
    if(fd == -1)
        ;  // handle error

    off_t fileSizeMinus1 = lseek(fd, -1, SEEK_END);
    if(fileSizeMinus1 == (off_t)-1)
        ;  // handle error

    // We're assuming that a newline is a bare LF '\n' here.  The CRLF case
    // is left as an exercise (hint: see the Windows case above)
    char lastChar;
    if(read(fd, &lastChar, 1) != 1)
        ;  // handle error

    if(lastChar == '\n')
    {
        if(ftruncate(fd, fileSizeMinus1) == -1)
            ;  // handle error
        // else success!
    }
    // else the file does not end in a newline

    close(fd);  // and we're done
#endif
}

The most efficient method would be to seek to the end of the file and move the end-of-file pointer backwards. Unfortunately this is not portable because there is no standard way of setting the end-of-file pointer in either the C or C++ standard libraries. You need to use a platform-specific function such as SetEndOfFile on Windows or ftruncate on POSIX. For example:

void RemoveFinalNewline(const char *filename)
{
#if defined(_WIN32)
    HANDLE hFile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if(hFile == INVALID_HANDLE_VALUE)
        ;  // handle error

    LARGE_INTEGER fileSize;
    if(GetFileSizeEx(hFile, &fileSize) == 0)
        ;  // handle error
    if(fileSize.QuadPart < 2)
        ;  // this case is left as an exercise to the reader

    LARGE_INTEGER newFilePtr;
    newFilePtr.QuadPart = -2;
    if(SetFilePointerEx(hFile, &newFilePtr, NULL, FILE_END) == 0)
        ;  // handle error

    char lastTwoBytes[2];
    if(ReadFile(hFile, lastTwoBytes, 2, NULL, NULL) == 0)
        ;  // handle error

    if(lastTwoBytes[1] == '\n')
    {
        fileSize.QuadPart--;
        if(lastTwoBytes[0] == '\r')
            fileSize.QuadPart--;
        if(SetFilePointerEx(hFile, &fileSize, NULL, FILE_BEGIN) == 0)
            ;  // handle error
        if(SetEndOfFile(hFile) == 0)
            ;  // handle error
        // Success!
    }
    // else the file didn't end in a newline

    CloseHandle(hFile);  // and we're done
#else  // POSIX case; the non-Windows, non-POSIX case is left as an exercise
    int fd = open(filename, O_RDWR);
    if(fd == -1)
        ;  // handle error

    off_t fileSizeMinus1 = lseek(fd, -1, SEEK_END);
    if(fileSizeMinus1 == (off_t)-1)
        ;  // handle error

    // We're assuming that a newline is a bare LF '\n' here.  The CRLF case
    // is left as an exercise (hint: see the Windows case above)
    char lastChar;
    if(read(fd, &lastChar, 1) != 1)
        ;  // handle error

    if(lastChar == '\n')
    {
        if(ftruncate(fd, fileSizeMinus1) == -1)
            ;  // handle error
        // else success!
    }
    // else the file does not end in a newline

    close(fd);  // and we're done
#endif
}
久伴你 2024-10-03 17:21:29

C++11 或更高版本 - 删除尾随空格(换行符、制表符、空格...):

std::string readAndTrimTrailingSpaces(std::string const & filePath)
{
    std::ifstream file(filePath);
    std::string   buffer(std::istreambuf_iterator<char>{file}, {});

    while (!buffer.empty() && std::isspace(buffer.back()))
        buffer.pop_back();

    return buffer;
}

C++11 or higher - removes trailing whitespaces (newlines, tabs, spaces, ...):

std::string readAndTrimTrailingSpaces(std::string const & filePath)
{
    std::ifstream file(filePath);
    std::string   buffer(std::istreambuf_iterator<char>{file}, {});

    while (!buffer.empty() && std::isspace(buffer.back()))
        buffer.pop_back();

    return buffer;
}
﹏半生如梦愿梦如真 2024-10-03 17:21:29

您需要从文件中读取所有内容,然后以不存在空行的方式或您想要的方式再次写入内容。

You need to read all the contents from file, and write the contents again in such a way that no empty line exists, or the way you want.

想念有你 2024-10-03 17:21:29

您可以创建一个简单的过滤器,如下所示应用:

remove_empty_last_line < input.txt > output.txt

或者,您可以创建自己的文件输入流 ala:

#include <fstream>

std::ifstream myin(filename);

然后,代码将类似于(未经测试)...

char c, d, e;

if (cin.get(c))
    if (cin.get(d))
    {
        while (cin.get(e))
        {
            cout << d;
            c = d;
            d = e;
        }
        if (c != '\n' || d != '\n')
            cout << d;
    }
    else
        cout << c;

(如果需要,请将 myin 替换为 cin,然后是 myin.close()) 。不需要使用 std::strings 来完成如此简单的事情:它们只会减慢一切。 C(以及 C++)的一大优势是能够一次有效地处理一个字符的数据。

You can create a simple filter, applied as in:

remove_empty_last_line < input.txt > output.txt

Or, you can create your own file input stream ala:

#include <fstream>

std::ifstream myin(filename);

Then, the code would resemble (untested)...

char c, d, e;

if (cin.get(c))
    if (cin.get(d))
    {
        while (cin.get(e))
        {
            cout << d;
            c = d;
            d = e;
        }
        if (c != '\n' || d != '\n')
            cout << d;
    }
    else
        cout << c;

(Substitute myin for cin if desired, then myin.close()). No need to use std::strings for something so simple: they just slow everything down. One of the great strengths of C (and hence C++) is being able to efficiently process data a character at a time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文