如何让文件流检查重复的追加?

如何解决如何让文件流检查重复的追加?

所以,我正在编写一个 C++ 程序(嗯,实际上是 RpgMaker 2003 的 .dll 插件),我有这样的代码:

#include <DynRPG/DynRPG.h>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

std::map<std::string,std::string> configuration;

bool onStartup(char *pluginName) {
               // We load the configuration from the DynRPG.ini file here
               configuration = RPG::loadConfiguration(pluginName);
               return true; // Don't forget to return true so that the start of the game will continue!
}

bool onComment( const char* text,const RPG::ParsedCommentData*   parsedData,RPG::EventScriptLine*   nextScriptLine,RPG::EventScriptData*   scriptData,int     eventId,int     pageId,int     lineId,int*    nextLineId )
{
    std::string cmd = parsedData->command;
    std::string filecode;
    std::string scanfile;
    string FileName;

    if(!cmd.compare("file_string")) //new code
    {
        ofstream myfile;
        myfile.open ("dynstore.txt",ios::app);
        myfile << parsedData->parameters[0].text << "\n";
        myfile.close();
        return false;
    }
    if(!cmd.compare("store_file")) //new code
    {
        ofstream myfile;
        myfile.open ("dynstore.txt",ios::app);
        myfile << RPG::actors[parsedData->parameters[0].number]->name << "\n";
        myfile.close();
        return false;
    }
    if(!cmd.compare("load_file")) //new code
    {
        ifstream myfile;
        myfile.open ("dynstore.txt");
        if(myfile.good()) //this should skip if the file doesn't exist.
        {
            getline (myfile,filecode);
            RPG::actors[parsedData->parameters[0].number]->name = filecode;
        }
        myfile.close();
        return false;
    }

    //These first three allow only storage using dynstore.

    if(!cmd.compare("create_file")) //custom file name,plus storing text
    {
        FileName = parsedData->parameters[0].text;
        ofstream myfile;
        myfile.open (FileName.c_str(),ios::app);
        myfile << parsedData->parameters[1].text << "\n";
        myfile.close();
        return false;
    }
    //This stores a word and makes a new line

    if(!cmd.compare("create_save")) //custom file name,plus storing text
    {
        int GameFile = RPG::variables[3351];

        ofstream myfile;
        if(GameFile == 0)
        {
            FileName = parsedData->parameters[0].text;
            myfile.open (FileName.c_str(),ios::app);
        }
        if(GameFile == 1)
        {
            myfile.open ("Save01.txt",ios::app);
        }
        if(GameFile == 2)
        {
            myfile.open ("Save02.txt",ios::app);
        }
        if(GameFile == 3)
        {
            myfile.open ("Save03.txt",ios::app);
        }
        if(GameFile == 4)
        {
            myfile.open ("Save04.txt",ios::app);
        }
        if(GameFile == 5)
        {
            myfile.open ("Save05.txt",ios::app);
        }
        if(GameFile == 6)
        {
            myfile.open ("Save06.txt",ios::app);
        }
        myfile << parsedData->parameters[1].text << "\n";
        myfile.close();
        return false;
    }
    //This stores a word and makes a new line

    if(!cmd.compare("make_file")) //custom file name,ios::app);
        myfile << RPG::actors[parsedData->parameters[1].number]->name;
        myfile.close();
        return false;
    }
    //This stores a name

    if(!cmd.compare("read_file")) //sets data info to name for easy read
    {
        FileName = parsedData->parameters[0].text;
        ifstream myfile;
        myfile.open (FileName.c_str());
        if(myfile.good()) //this should skip if the file doesn't exist.
        {
            getline (myfile,filecode);
            RPG::actors[parsedData->parameters[1].number]->name = filecode;
        }
        myfile.close();
        return false;
    }
    if(!cmd.compare("clear_file")) //sets data info to name for easy read
    {
        FileName = parsedData->parameters[0].text;
        ofstream myfile;
        myfile.open (FileName.c_str());
        myfile.clear();
        myfile.close();
        return false;
    }

     if(!cmd.compare("scan_save"))
    {
        //Attempt ONE to scan the file for a string
        //this one works by turning on a switch if the string is found

        int GameFile = RPG::variables[3351];

        ifstream myfile;
        if(GameFile == 0)
        {
            FileName = parsedData->parameters[0].text;
            myfile.open (FileName.c_str());
        }
        if(GameFile == 1)
        {
            myfile.open ("Save01.txt");
        }
        if(GameFile == 2)
        {
            myfile.open ("Save02.txt");
        }
        if(GameFile == 3)
        {
            myfile.open ("Save03.txt");
        }
        if(GameFile == 4)
        {
            myfile.open ("Save04.txt");
        }
        if(GameFile == 5)
        {
            myfile.open ("Save05.txt");
        }
        if(GameFile == 6)
        {
            myfile.open ("Save06.txt");
        }
        scanfile = parsedData->parameters[1].text;
        int switchnum = parsedData->parameters[2].number;

        if(myfile.good()) //this should skip if the file doesn't exist.
        {
             for(std::string temp;!myfile.eof();std::getline(myfile,temp))
             {
                 if(temp.find(scanfile)!=std::string::npos)
                 {
                     RPG::switches[switchnum] = true;
                //Turns on the switch if the string has been found in the file
                //ideally,I'd want to save a new name using the scanfile,but I can't figure out how to copy it
                 }
             }
        }
        myfile.close();
        return false;
    } //This checks only the current save,defaulting to the input if none exists

    if(!cmd.compare("scan_file"))
    {
        //Attempt ONE to scan the file for a string
        //this one works by turning on a switch if the string is found
        FileName = parsedData->parameters[0].text;
        ifstream myfile;
        myfile.open (FileName.c_str());
        scanfile = parsedData->parameters[1].text;
        int switchnum = parsedData->parameters[2].number;

        if(myfile.good()) //this should skip if the file doesn't exist.
        {
             for(std::string temp;!myfile.eof();std::getline(myfile,but I can't figure out how to copy it
                 }
             }
        }
        myfile.close();
        return false;
    }

    if(!cmd.compare("file_good"))
    {
        //Checks for the existence of a file.
        FileName = parsedData->parameters[0].text;
        ifstream myfile;
        myfile.open (FileName.c_str());
        int switchnum = parsedData->parameters[1].number;

        if(myfile.good()) //this should skip if the file doesn't exist.
        {
             RPG::switches[switchnum] = true;
        }

        else
        {
            RPG::switches[switchnum] = false;
        }

        myfile.close();
        return false;
    }

    //End of cmd
    return true;
}

通常,.dll 插件是这样工作的:它通过链接器设置运行 DynRPG 标头,并将 RpgMaker 的 RPG_RT.exe 作为其主机参数。 onStartup 和 onComment 是 DynRPG 特定的代码,可与 RpgMaker 兼容运行。你不需要知道大部分,除了知道这些 if(!cmd.compare(" ")) 代码基本上是 RpgMaker 的命令。所以,我告诉各种文件打开文本文件,但我一直遇到问题:

  1. 我有一个清除文件的代码,它确实清除了文件。但我认为 它创建文件是为了清除它,而不是跳过 如果它不存在。事实上,我认为这是一个长期存在的问题,我 不知道如何让代码跳过不存在的文件名,所以它 如果代码检查文件,则会生成新文件。
  2. 如果可能,该清除文件实际上应该删除文件而不是 而不仅仅是让它成为空白。
  3. 它将信息附加到我制作的文件中(似乎没有 是任何内存泄漏),但它不会检查以确保我 尚未输入相同的单词或短语。当我写作 进入文件,我想检查 但我想我只知道如何检查 加载输出时输出,而不是在输入之前。我想避免 重复。目前,我有一个名为“awards.txt”的文件(可解锁 奖),我有同一个词的 6 个实例的文件。 我希望它只编写一次相同的代码。这是我的主要问题。

不要给出愚蠢的建议,假设我会理解你的意思。给我看看实际代码。我几乎没有通过阅读和改编其他教程拼凑这么多代码,而且我没有计算机科学学位(我是历史专业的,所以 C++ 代码理论对我来说并不总是有意义)。哦,呃,并不是所有的头文件都是必需的,我倾向于包含比我需要的更多以防万一。

解决方法

第 1 点

    if(!cmd.compare("clear_file")) //sets data info to name for easy read
    {
        FileName = parsedData->parameters[0].text;
        ofstream myfile;
        myfile.open (FileName.c_str());
        myfile.clear();
        myfile.close();
        return false;
    }

myfile.open (FileName.c_str()); 中使用的默认文件打开模式将创建一个空文件,覆盖现有文件。凉爽的。空文件是您想要的,但是,它创建了一个不存在的空文件。为避免这种情况,您需要指定一种不会创建新文件的打开模式。 Using this groovy table here,如果文件没有退出而不是打开它,则指定 in 打开模式将引发错误。不幸的是,如果您继续阅读,您会发现没有任何 openmodes 组合可以在不创建新文件的情况下截断(清除)文件。

那是不是很糟糕?

在 C++17 中,我们可以使用 <filesystem> Library's resize_file function

std::error_code code;
std::filesystem::resize_file(FileName,code);
// test code here if you care. Someone else could have the file open and prevent clearing.

在 C++17 之前,最容易使用系统特定的 API 调用。你在上面提到了 DLL,所以我将假设一个 Windows 目标

HANDLE h = CreateFileA(FileName.c_str(),GENERIC_WRITE,NULL,TRUNCATE_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (h != INVALID_HANDLE_VALUE)
{
    CloseHandle(h);
}

Documentation on CreateFileA。请注意,我使用 CreateFileA 而不是 CreateFileWCreateFile,因为 FileName 不包含宽字符。

可能会有更直接的调用。我对 Win132 API 不太熟悉。

像 Linux 这样的 POSIX 兼容目标(也许是 Mac。我对 Mac 的了解更少)uses truncate

int code = truncate(FileName.c_str(),0);
// test code here and look at errno if you care. Someone else could have the file open.

如果幸运的话,编译器开发人员会为您将 truncate 移植到 Windows 并简化您的工作,因为您只需要支持一个目标。

附注

因为 openmode 实际是在清除文件,所以我们应该看看 myfile.clear(); 做了什么:清除流上的错误标志。通常,当流操作失败时,会设置错误标志,以便您可以检查哪里出了问题。当设置了任何错误标志时,流拒绝处理任何进一步的事务并立即返回。在每个事务之后检查流的状态以确保它工作是你的程序员,因为如果它没有并且你不检查,你永远不会知道。流状态和错误标志是您收到的唯一警告。

因此,您检查标志,处理标记的错误,然后调用 clear 以表示您已解决问题并准备恢复读写。注意:有时处理错误需要您尽早清除标志以删除、读出错误数据,以便程序不会立即找到相同的垃圾并在您返回到代码的常规流程时再次失败。

第 2 点

删除文件...现在更容易了。在 C++17 中

std::error_code code;
std::filesystem::remove("test",code);
// Wrap in an if and test code if you care about failure. I would. 
// If it's file not found,cool!

在旧世界,

if (remove(FileName.c_str()) !=)
{
    //check errno to find out why
}

Documentation for std::filesystem::remove

Documentation for remove

第 3 点

我刚看到时间,我需要停下来。您应该从问题中删除第三点,因为这是一个完全不同的问题,值得提出自己的问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-