0

我有一个 JUnit 测试,它测试我一直在处理的一段代码,它使用临时文件来执行某些功能。无论出于何种原因,测试在 OSX 上通过,但在 Windows 7 上失败。为了简化事情,我将测试复制到一个新文件中,并将其归结为尽可能简单,同时仍然显示错误。

基本上,我通过将逗号分隔的键值对写入文件来初始化临时文件(然后断言它存在,它确实存在)。然后,我尝试根据键替换行的值。updateValueForKey()具有布尔值“checkOldVal”,如果为真,则要求oldVal传入的值与文件中的值匹配。此测试在 Windows 上失败,并在 OSX 上通过,无论是真还是假

Windows Java 版本:1.6.0_45

OSX Java 版本:1.6.0_65

代码如下:

public class SimpleTempFileTest {

ReadWriteLock _fileLock = null;
File _file = null;

public SimpleTempFileTest() {
}

@Test
public void simpleTempFileTest() throws Exception {
    _file = File.createTempFile("testCsv", null);
    _file.deleteOnExit();
    _fileLock = new ReentrantReadWriteLock();
    BufferedWriter writer = null;
    try {
        _fileLock.writeLock().lock();
        writer = new BufferedWriter(new FileWriter(_file, true));
        writer.append("foo,bar");
        writer.newLine();
    } finally {
        if (writer != null) {
            writer.close();
        }
        _fileLock.writeLock().unlock();
    }

    BufferedReader br = new BufferedReader(new FileReader(_file));
    String line = br.readLine();
    assertTrue("Unexpected value. Line=" + line, line.equals("foo,bar"));
    assertTrue("Unexpected value. Line=" + line, br.readLine() == null);
    br.close();

    //Fails whether checkOldVal is true or false
    updateValueForKey("foo", "bar", "baz", true);
    br = new BufferedReader(new FileReader(_file));
    line = br.readLine();
    //Everything up to this point passes, but the following assertion fails
    assertTrue("Unexpected value. Line=" + line, line.equals("foo,baz"));
    assertTrue("Unexpected value. Line=" + line, br.readLine() == null);
    br.close();
}

String updateValueForKey(String key, String oldVal, String newVal, boolean checkOldVal) throws FileNotFoundException, IOException {
    BufferedReader br = null;
    BufferedWriter writer = null;
    File temp = null;
    try {
        _fileLock.writeLock().lock();
        br = new BufferedReader(new FileReader(_file));
        temp = File.createTempFile("csvTmp", ".tmp");
        writer = new BufferedWriter(new FileWriter(temp, true));
        boolean seek = true;
        String line;
        while ((line = br.readLine()) != null) {
            if (seek) {
                String[] nvp = line.split(",");
                System.out.println("nvp[0]=" + nvp[0] + ", nvp[1]=" + nvp[1]);
                if (nvp[0].equalsIgnoreCase(key)) {
                    if (nvp[1].equals(oldVal) || !checkOldVal) {
                        String lineToWrite = key + "," + newVal;
                        System.out.println("Writing " + lineToWrite);
                        writer.write(lineToWrite);
                        writer.newLine();
                        seek = false;
                        continue;
                    } else {
                        System.out.println("Failed for " + key + ". Val incorrect.");
                        return "Password incorrect";
                    }
                }
            }
            writer.write(line);
            writer.newLine();
        }
        _file.delete();
        temp.renameTo(_file);
        return null;
    } finally {
        if (br != null) {
            br.close();
        }
        if (writer != null) {
            writer.close();
        }
        if (temp != null) {
            temp.delete();
        }
        _fileLock.writeLock().unlock();
    }
}
}

有什么想法吗?谢谢。

4

1 回答 1

0

该问题与 Windows 和 Unix 处理文件锁定的方式之间的差异有关。在 Unix 上,一个进程可以写入文件,而另一个进程可以打开它来读取它。Windows 不允许这样做。

全面披露:如果 Java 未能对文件执行 IO 类型的操作,我预计 Java 会抛出 IOException,暂时忘记了其中许多操作返回布尔值,指定操作是否成功。

长话短说,在 updateValueForKey() 快结束时,我删除了 _file,并将 tmp 重命名为 _file,temp 仍然打开 FileWriter,_file 仍然打开 BufferedReader。基本上,我不得不将 _file.delete 和 temp.renameTo() 移到 finally 块下方。

于 2013-11-01T19:04:31.090 回答