gpt4 book ai didi

java - Windows:移动先前映射到内存中的文件失败

转载 作者:可可西里 更新时间:2023-11-01 11:30:31 25 4
gpt4 key购买 nike

-:= 编辑为简化 =:-


在将代码从 Linux (Ubuntu LTS 12.4) 环境移植到 Windows Server 2008 的过程中,我遇到了一个问题。

我需要使用内存映射文件,但我无法在 Windows 上防止以下错误。

此问题在下面的单元测试中重现。 2 个测试在 Linux 上成功,但在 Windows 上测试 testWithRandowmAccessFile 失败,堆栈跟踪在底部。

testWithRandowmAccessFile 测试失败的根本原因是什么?
我应该如何在 Windows 上实现它?

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import org.apache.commons.io.IOUtils;
import org.junit.Test;

public class TestIOOnWindows {

@Test
public void testWithRandowmAccessFile() throws IOException {
final File sourceFile = new File("source.txt");
final File manipulatedFile = new File("manipulated.txt");
final File targetFile = new File("target.txt");

try
(
FileInputStream sourceInputStream = new FileInputStream(sourceFile);
RandomAccessFile manipulated = new RandomAccessFile(manipulatedFile, "rw");
FileChannel fcOut = manipulated.getChannel()
)
{
byte[] sourceBytes = new byte[Long.valueOf(sourceFile.length()).intValue()];
IOUtils.read(sourceInputStream, sourceBytes);

final int length = sourceBytes.length;

// ========= with this single line on Windows, the move fails ======
MappedByteBuffer byteBuffer = fcOut.map(FileChannel.MapMode.READ_WRITE, 0, length);
// commenting this line would not prevent the error on Windows
byteBuffer.put(sourceBytes, 0, length);
}

Files.move(
Paths.get(manipulatedFile.getAbsolutePath()),
Paths.get(targetFile.getAbsolutePath()),
StandardCopyOption.REPLACE_EXISTING);
}

@Test
public void testWithFileOutputStream() throws IOException {
final File sourceFile = new File("source.txt");
final File manipulatedFile = new File("manipulated.txt");
final File targetFile = new File("target.txt");

try
(
FileInputStream sourceInputStream = new FileInputStream(sourceFile);
FileOutputStream manipulatedOutputStream = new FileOutputStream(manipulatedFile);
FileChannel fcIn = sourceInputStream.getChannel();
FileChannel fcOut = manipulatedOutputStream.getChannel()
)
{
final long length = sourceFile.length();

// ========= with this single line on Windows, the move succeed ====
fcIn.transferTo(0, length, fcOut);
}

Files.move(
Paths.get(manipulatedFile.getAbsolutePath()),
Paths.get(targetFile.getAbsolutePath()),
StandardCopyOption.REPLACE_EXISTING);
}
}


添加我在 Windows 上从命令提示符运行单元测试时得到的跟踪跟踪。

There was 1 failure:
1) testWithRandowmAccessFile(TestIOOnWindows) java.nio.file.FileSystemException: C:\Users\Administrator\AppData\Local\Temp\manipulated.txt -> C:\Users\Administrator\AppData\Local\Temp\target.txt: The process cannot access the file because it is being used by another process.

at sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsFileCopy.move(Unknown Source)
at sun.nio.fs.WindowsFileSystemProvider.move(Unknown Source)
at java.nio.file.Files.move(Unknown Source)
===> at TestIOOnWindows.testWithRandowmAccessFile(TestIOOnWindows.java:40) <===
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:24)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at org.junit.runner.JUnitCore.run(JUnitCore.java:136)
at org.junit.runner.JUnitCore.run(JUnitCore.java:117)
at org.junit.runner.JUnitCore.runMain(JUnitCore.java:98)
at org.junit.runner.JUnitCore.runMainAndExit(JUnitCore.java:53)
at org.junit.runner.JUnitCore.main(JUnitCore.java:45)

FAILURES!!!
Tests run: 2, Failures: 1

最佳答案

在 Java 中,文件映射是垃圾收集器,并且不支持强制销毁映射的方法。

来自FileChannel.map()文档:

The buffer and the mapping that it represents will remain valid until the buffer itself is garbage-collected.

A mapping, once established, is not dependent upon the file channel that was used to create it. Closing the channel, in particular, has no effect upon the validity of the mapping.

在 Sun 的 JDK 中,您可以通过在执行文件移动之前强行破坏映射来测试这确实是罪魁祸首:

import sun.nio.ch.DirectBuffer;
import sun.misc.Cleaner;
[...]
if (byteBuffer.isDirect()) {
Cleaner cleaner = ((DirectBuffer) byteBuffer).cleaner();
cleaner.clean();
}
// move file

关于java - Windows:移动先前映射到内存中的文件失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21337078/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com