【问题标题】:Linux vs. Windows File.delete()Linux 与 Windows File.delete()
【发布时间】:2013-05-13 16:55:41
【问题描述】:

与 Linux 相比,我很难理解 Windows 如何处理文件。我正在尝试删除我用作“数据库”的文件中的条目(它只是一个常规文件)。不幸的是,Java 没有提供这样做的方法,所以我必须将除我要删除的条目之外的所有条目复制到临时文件中,删除旧数据库,创建一个新的空数据库文件,将临时文件的内容复制到新的数据库文件,然后删除临时文件。

这是我的函数的代码:

private void removeSelectedItem(String entryToRemove) {

    //original database file
    File database = new File("catalog");

    //all entries except selected will be written here first
    File temp = new File("temp");

    boolean endOfFileFlag = false;
    String line = "";

    try {

        //used for reading original database file
        BufferedReader databaseReader =
            new BufferedReader(new FileReader(database));

        //used for writing to newly-created temp file
        BufferedWriter tempWriter =
            new BufferedWriter(new FileWriter(temp, true));

        /*
         * Read original database line by line and test to see if the line
         * has the course prefix and id. If it does, it won't be written to
         * the temp file.
         */
        while (endOfFileFlag == false) {

            line = databaseReader.readLine();

            /*
             * This code is ugly. If possible, this check needs to be
             * made in the conditions of the while loop.
             */
            if (line == null) {

                endOfFileFlag = true;
                break;

            }

            //tests to see if the line is to be removed
            if ( !line.contains(entryToRemove))
                tempWriter.write(line + "\r\n");

        }

        endOfFileFlag = false; //reset this for the next loop
        databaseReader.close(); //database will be deleted
        tempWriter.close(); //temp file is written
        database.delete(); //delete this to create a new updated one below

        database.createNewFile();

        //writes to the new database
        BufferedWriter databaseWriter =
                new BufferedWriter(new FileWriter(database, true));

        //reads from the temp file
        BufferedReader tempReader =
            new BufferedReader(new FileReader(temp));

        //read temp line by line and add each line to a new catalog file
        while (endOfFileFlag == false) {

            line = tempReader.readLine();

            /*
             * This code is ugly. If possible, this check needs to be made
             * in the conditions of the while loop. Attempts thus far have
             */
            if(line == null){

                endOfFileFlag = true;
                break;

            }

            databaseWriter.write(line + "\r\n");

        }

        tempReader.close(); //temp will be deleted
        databaseWriter.close(); //new database has been written
        temp.delete(); //temp file no longer needed

        setUpInfo(); //update the lists with the new catalog info

    }catch(IOException e){

        System.out.println("removeSelectedItem()");
        e.printStackTrace();

    }

}

这段代码(“\r\n”除外,在 Linux 中只有“\n”)在 Linux 下完美执行,但在 Windows 中,我发现当我激活事件处理程序以删除条目时,程序只会添加额外的条目。调试后我发现对database.delete() 的调用实际上并没有删除数据库文件,而对temp.delete() 的调用正在删除临时文件(就像它应该删除的那样)。我发现这很奇怪,所以我检查了文件的权限并将它们设置为“读/写”。我尝试了在互联网上找到的以下修复:

endOfFileFlag = false; //reset this for the next loop
databaseReader.close(); //database will be deleted
tempWriter.close(); //temp file is written
database.delete(); //delete this to create a new updated one below
//new code
database = null;
System.gc();

但它没有用。我想不出还有什么可能发生的事情。

【问题讨论】:

    标签: java delete-file platform-specific


    【解决方案1】:

    AFAIK,没有操作系统支持删除文件的一部分(除了结尾)

    您无法删除已打开的文件,因此您必须确保在所有位置都将其关闭,但您可以创建一个临时文件并将其重命名为原始文件。 (无需复制回来)

    我可以这样写

    public static void removeLine(String filename, String line) {
        File from = new File(filename);
        File tmp = new File(filename + ".tmp");
        PrintWriter pw = null;
        BufferedReader br = null;
        try {
            pw = new PrintWriter(tmp);
            br = new BufferedReader(new FileReader(from));
            boolean found = false;
            for (String line2; (line2 = br.readLine()) != null; )
                if (line2.equals(line))
                    found = true;
                else
                    pw.println(line2);
            pw.close();
            br.close();
            if (found) {
                from.delete();
                tmp.renameTo(from);
            } else {
                tmp.delete();
            }
        } catch (IOException e) {
            // log error.
            try { if (br != null) br.close(); } catch (IOException ignored) { }
            if (pw != null) pw.close();
        }
    }
    

    【讨论】:

    • 我知道没有操作系统支持从文件中间删除数据。我的困惑是为什么 Windows 不会删除该文件,而 Linux 会。 Linux 不允许我删除附加了ReaderWriter 的文件。我不得不承认我不知道你可以重命名文件(这是我缺乏研究,我希望我能这样做,因为它使算法更有效),但代码仍然没有改变这样一个事实该文件不会被删除。
    • Windows 更渴望锁定文件并阻止您对其执行操作。 Windows XP 可以阻止您删除您曾经打开过的文件,这至少可以说是烦人的。
    • 是的,我认为这与此有关。顺便说一句,我添加了您的建议,即重命名临时文件,而不是将所有临时文件的内容复制到使用我的 Linux 构建的新数据库文件中,它运行良好,非常感谢。
    【解决方案2】:

    至于您的\r\n\n 问题,请使用System.getProperty("line.separator")(或Java 7 的System.lineSeparator())来确定您的行尾字符序列。

    确保您已在所有位置关闭该文件。尝试使用Path 类来读取文件。我不知道你为什么现在不能删除它,但也许这会解决问题。

    此外,您应该为您的while 循环使用以下结构(以避免使用break):

    while (endOfFileFlag == false) {
    
        line = databaseReader.readLine();
    
        if (line == null)
            endOfFileFlag = true;
        else if ( !line.contains(entryToRemove))
            tempWriter.write(line + "\r\n");
    
    }
    

    【讨论】:

    • @Hugo,您是否也将第二个 if 语句更改为 if else
    • 哇哦。那是我的错。我第一次回答时有点跑题了,所以我的两个答案都不完整。有什么理由我不应该使用 break 吗?而且,似乎使用Path 创建BufferedReader 而不是仅仅使用普通文件会给我同样的问题,即使实现更复杂,因为BufferedReader 仍然导致文件被锁定。我现在无法对此进行测试,但其他人可以对此进行权衡吗?
    • 抱歉重复发帖,但感谢您的回答,因为它对我也有帮助。我只能将其中一个标记为已接受的答案。
    • @Hugo,使用 break 被认为是草率的,因为它会促进循环中不正确/低效地使用标记值。使用break 并没有什么“错误”,但它会导致不良习惯,导致您在不应该使用break 时使用。
    • 哦,好吧,我明白了。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2012-05-08
    • 2016-08-28
    • 1970-01-01
    • 2016-04-06
    • 2012-08-06
    • 2018-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多