Java 7 WatchService -进程不能访问该文件,因为它正在被另一个进程使用



我按照观察目录更改Java7 nio2教程,使用代码样例WatchDir.java递归地监视目录的整个内容。

代码如下:

// Get list of events for the watch key.
for (WatchEvent<?> event : key.pollEvents()) {
// This key is registered only for ENTRY_CREATE events, but an OVERFLOW event 
// can occur regardless if events are lost or discarded.
if (event.kind() == OVERFLOW) {
    continue;
}
// Context for directory entry event is the file name of entry.
@SuppressWarnings("unchecked")
WatchEvent<Path> ev = (WatchEvent<Path>)event;
Path fileName = ev.context();
Path fullPath = dir.resolve(fileName);
try {
    // Print out event.
    System.out.print("Processing file: " + fileName);
    processed = fileProcessor.processFile(fullPath);
    System.out.println("Processed = " + processed);
    if (processed) {
        // Print out event.
        System.out.println(" - Done!");
    }
} 
catch (FileNotFoundException e) {
    System.err.println("Error message: " + e.getMessage());
}
catch (IOException e) {
    System.err.println("Error processing file: " + fileName.toString());
    System.err.println("Error message: " + e.getMessage());
}

好的,所以问题(我肯定做了一些愚蠢的事情)在这里:

processed = fileProcessor.processFile(fullPath);

它的作用是这样的:

public synchronized boolean processFile(Path fullPath) throws IOException {
String line;
String[] tokens;
String fileName = fullPath.getFileName().toString();
String fullPathFileName = fullPath.toString();
// Create the file.
File sourceFile = new File(fullPath.toString());
// If the file does not exist, print out an error message and return.
if (sourceFile.exists() == false) {
    System.err.println("ERROR: " + fullPathFileName + ": No such file");
    return false;
}
// Check file extension.
if (!getFileExtension(fullPathFileName).equalsIgnoreCase("dat")) {
    System.out.println(" - Ignored.");
    return false;
}
// Process source file.
try (BufferedReader bReader = new BufferedReader(new FileReader(sourceFile))) {
    int type;
    // Process each line of the file.
    while (bReader.ready()) {
        // Get a single line.
        line = bReader.readLine();
        // Get line tokens.
        tokens = line.split(delimiter);
        // Get type.
        type = Integer.parseInt(tokens[0]);
        switch (type) {
        // Type 1 = Salesman.
        case 1:
            -> Call static method to process tokes.
            break;
        // Type 2 = Customer.
        case 2:
            -> Call static method to process tokes.
            break;
        // Type 3 = Sales.
        case 3:
            -> Call static method to process tokes.
            break;
        // Other types are unknown!
        default:
            System.err.println("Unknown type: " + type);
            break;
        }
    }
    PrintStream ps = null;
    try {
        // Write output file.
        // Doesn't matter. 
    } 
    finally {               
        if (ps != null) {
            ps.close();
        }
    }
    return true;
}
}

第一次处理事件时,一切正常!即使有多个文件要处理。但是在连续的时间里,我得到这个错误消息:

进程不能访问该文件,因为它正在被另一个进程使用

我在这里做错了什么?怎样才能成功处理连续的文件?

我忘了说的两个重要的注意事项:

  1. 当我在调试模式下运行应用程序时,它可以工作。

编辑:如果我在尝试使用文件之前添加一个sleep,它会工作:

Thread.sleep(500);
// Process source file.
try (BufferedReader bReader = new BufferedReader(new FileReader(sourceFile))) {

那么,有没有可能是Windows没有及时解锁文件呢?我怎样才能(以适当的方式)解决这个问题?

好了,我找到了一个解决方案。我不知道这是不是最好的方法,但它确实有效。不幸的是,file. canread()和file. canwrite()都返回true,即使文件仍然被Windows锁定。所以我发现,如果我尝试用相同的名字"重命名"它,我就知道Windows是否正在处理它。这就是我所做的:

    while(!sourceFile.renameTo(sourceFile)) {
        // Cannot read from file, windows still working on it.
        Thread.sleep(10);
    }

Arundev给出的解决方案对我很有效。

我需要添加睡眠时间,否则它将无法为多个请求工作,并用于获得错误"进程无法访问该文件,因为它正在被另一个进程使用"

if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
// now do your intended jobs ... 

我也遇到过类似的问题。但是我的文件在复制的时候并没有被锁定。如果我在创建事件后试图读取它,它是空的

我认为在你的情况下,没有必要的技巧,你可以简单地处理错误,如果你得到错误,你可以执行睡眠,然后再试一次。但对我来说,这并不适合我。我没有得到错误。所以我尝试了你的解决方案,我明白这对我来说也是不可接受的,因为我除了读书没有其他权利。所以我可以提出我的"诀窍"。我使用java.io.RandomAccessFile:

List<String> lines = null;
while(true){
    try( RandomAccessFile raf = new RandomAccessFile( fileFullPath.toFile() , "r" ) ){
        lines = Files.readAllLines( fileFullPath , Charset.forName(ENCODING) );
        break;
    }catch(FileNotFoundException ex){
        LOG.warn("File isn't yet completed: {}",ex.getMessage() );
        LOG.info( "Waiting {} for next attempt to read it" , SLEEP_INTERVAL_READING );
        try {
            Thread.sleep(SLEEP_INTERVAL_READING);
        } catch (InterruptedException e) {
            LOG.error("Waiting was interrupted",e);
        }
    }catch(Exception ex){
        LOG.error("Error in reading file ",ex);
        clear();
        return false;
    }
} 

当事件类型为ENTRY_MODIFY时,请允许当前线程休眠几秒钟。我不能确切地告诉为什么会发生这种情况,但有时多个ENTRY_MODIFY事件在我的日志中打印。请根据文件大小设置休眠时间。

if(kind ==  StandardWatchEventKinds.ENTRY_MODIFY){
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
//toDo - something
}

相关内容

  • 没有找到相关文章

最新更新