Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:监视目录以移动大文件_Java_Directory_Watch - Fatal编程技术网

Java:监视目录以移动大文件

Java:监视目录以移动大文件,java,directory,watch,Java,Directory,Watch,我一直在写一个程序,监视一个目录,当在其中创建文件时,它会更改名称并将它们移动到一个新目录。在我的第一个实现中,我使用了Java的Watch Service API,当我测试1kb文件时,它工作得很好。出现的问题是,实际上创建的文件大小在50-300mb之间。发生这种情况时,WatcherAPI会立即找到该文件,但无法移动它,因为它仍在编写中。我试着将watcher放入一个循环(在文件被移动之前会产生异常),但这似乎效率很低 由于这不起作用,我尝试使用计时器,每隔10秒检查一次文件夹,然后在可能

我一直在写一个程序,监视一个目录,当在其中创建文件时,它会更改名称并将它们移动到一个新目录。在我的第一个实现中,我使用了Java的Watch Service API,当我测试1kb文件时,它工作得很好。出现的问题是,实际上创建的文件大小在50-300mb之间。发生这种情况时,WatcherAPI会立即找到该文件,但无法移动它,因为它仍在编写中。我试着将watcher放入一个循环(在文件被移动之前会产生异常),但这似乎效率很低

由于这不起作用,我尝试使用计时器,每隔10秒检查一次文件夹,然后在可能的时候移动文件。这就是我最终选择的方法

问题:在没有进行异常检查或持续比较大小的情况下,是否仍有信号表明文件写入完成?我喜欢对每个文件只使用一次WatcherAPI,而不是不断使用计时器检查(并遇到异常)

非常感谢所有回复


nt

写入另一个文件,作为原始文件已完成的指示。 I.g“fileorg.dat”正在增长,如果完成创建文件“fileorg.done”并检查 仅适用于“fileorg.done”

使用巧妙的命名约定,您应该不会遇到问题。

两种解决方案:

第一个是以下方面的细微变化:

对不完整的文件使用唯一前缀。类似于
myhugefile.zip.inc
而不是
myhugefile.zip
。上载/创建完成后重命名文件。从手表中排除.inc文件

第二种方法是使用同一驱动器上的不同文件夹创建/上载/写入文件,并在文件准备就绪后将其移动到关注的文件夹。如果它们在同一个驱动器上,移动应该是一个原子操作(我想,这取决于文件系统)


无论哪种方式,创建文件的客户端都必须做一些额外的工作。

我推测java.io.File.canWrite()将在文件编写完成后告诉您。

这是一个非常有趣的讨论,当然,这是一个简单的用例:等待一个新文件被创建,然后以某种方式对该文件做出反应。这里的竞争条件很有趣,因为这里的高级需求当然是获取一个事件,然后实际获取(至少)文件的读锁。对于大文件或只是大量文件创建,这可能需要整个工作线程池,这些线程周期性地尝试锁定新创建的文件,当它们成功时,实际执行工作。但正如我确信NT所意识到的,我们必须小心地做到这一点,以使其具有可扩展性,因为这最终是一种轮询方法,可扩展性和轮询并不是两个很好地结合在一起的词。

我今天遇到了同样的问题。我认为在文件实际导入之前的一个小延迟并不是什么大问题,我仍然希望使用NIO2 API。我选择的解决方案是,在对某个文件执行任何操作之前,等待10秒钟,直到该文件未被修改

实施的重要部分如下。程序将等待,直到等待时间到期或发生新事件。每次修改文件时,都会重置过期时间。如果在等待时间到期之前删除文件,则会将其从列表中删除。我使用poll方法,超时时间为预期的expirationtime,即(lastmodified+waitTime)-currentTime

private final Map<Path, Long> expirationTimes = newHashMap();
private Long newFileWait = 10000L;

public void run() {
    for(;;) {
        //Retrieves and removes next watch key, waiting if none are present.
        WatchKey k = watchService.take();

        for(;;) {
            long currentTime = new DateTime().getMillis();

            if(k!=null)
                handleWatchEvents(k);

            handleExpiredWaitTimes(currentTime);

            // If there are no files left stop polling and block on .take()
            if(expirationTimes.isEmpty())
                break;

            long minExpiration = min(expirationTimes.values());
            long timeout = minExpiration-currentTime;
            logger.debug("timeout: "+timeout);
            k = watchService.poll(timeout, TimeUnit.MILLISECONDS);
        }
    }
}

private void handleExpiredWaitTimes(Long currentTime) {
    // Start import for files for which the expirationtime has passed
    for(Entry<Path, Long> entry : expirationTimes.entrySet()) {
        if(entry.getValue()<=currentTime) {
            logger.debug("expired "+entry);
            // do something with the file
            expirationTimes.remove(entry.getKey());
        }
    }
}

private void handleWatchEvents(WatchKey k) {
    List<WatchEvent<?>> events = k.pollEvents();
    for (WatchEvent<?> event : events) {
        handleWatchEvent(event, keys.get(k));
    }
    // reset watch key to allow the key to be reported again by the watch service
    k.reset();
}

private void handleWatchEvent(WatchEvent<?> event, Path dir) throws IOException {
    Kind<?> kind = event.kind();

    WatchEvent<Path> ev = cast(event);
        Path name = ev.context();
        Path child = dir.resolve(name);

    if (kind == ENTRY_MODIFY || kind == ENTRY_CREATE) {
        // Update modified time
        FileTime lastModified = Attributes.readBasicFileAttributes(child, NOFOLLOW_LINKS).lastModifiedTime();
        expirationTimes.put(name, lastModified.toMillis()+newFileWait);
    }

    if (kind == ENTRY_DELETE) {
        expirationTimes.remove(child);
    }
}
private final Map expirationTimes=newHashMap();
私有长newFileWait=10000L;
公开募捐{
对于(;;){
//检索并删除下一个监视键,如果不存在则等待。
WatchKey k=watchService.take();
对于(;;){
long currentTime=new DateTime().getMillis();
如果(k!=null)
handleWatchEvents(k);
handleExpiredWaitTimes(当前时间);
//如果没有剩余的文件,停止轮询并阻止.take()
if(expirationTimes.isEmpty())
打破
long minexption=min(expirationTimes.values());
长超时=最小消耗电流时间;
调试(“超时:”+超时);
k=watchService.poll(超时,时间单位为毫秒);
}
}
}
私有void handleExpiredWaitTimes(长currentTime){
//为过期时间已过的文件启动导入
for(条目:expirationTimes.entrySet()){
if(entry.getValue()kind=event.kind();
WatchEvent ev=铸造(事件);
路径名=ev.context();
路径子项=目录解析(名称);
如果(种类==条目|修改|种类==条目|创建){
//更新修改时间
FileTime lastModified=Attributes.readBasicFileAttributes(子级,无后续链接)。lastModifiedTime();
expirationTimes.put(名称,lastModified.toMillis()+newFileWait);
}
如果(种类==条目\删除){
过期时间。删除(子项);
}
}

当我实现了一个文件系统监视程序来传输上传的文件时,我不得不处理类似的情况。我为解决此问题而实现的解决方案包括以下内容:

1-首先,维护未处理文件的映射(只要文件仍在复制,文件系统将生成Modify_事件,因此如果标志为false,您可以忽略它们)

2-在fileProcessor中,您从列表中选取一个文件并检查它是否被文件系统锁定,如果是,您将得到一个异常,只需捕获该异常并将线程置于等待状态(即10秒)然后重试,直到释放锁。处理文件后,您可以将该标志更改为true或将其从映射中删除

如果在等待时间段内传输同一文件的多个版本,则此解决方案将无效

干杯, Ramzi

虽然它不是
boolean locked = true;

while (locked) {
    RandomAccessFile raf = null;
    try {
            raf = new RandomAccessFile(file, "r"); // it will throw FileNotFoundException. It's not needed to use 'rw' because if the file is delete while copying, 'w' option will create an empty file.
            raf.seek(file.length()); // just to make sure everything was copied, goes to the last byte
            locked = false;
        } catch (IOException e) {
            locked = file.exists();
            if (locked) {
                System.out.println("File locked: '" + file.getAbsolutePath() + "'");
                Thread.sleep(1000); // waits some time
            } else { 
                System.out.println("File was deleted while copying: '" + file.getAbsolutePath() + "'");
            }
    } finally {
            if (raf!=null) {
                raf.close();    
            }
        }
}
if (kind == ENTRY_CREATE) {
            System.out.println("Creating file: " + child);

            boolean isGrowing = false;
            Long initialWeight = new Long(0);
            Long finalWeight = new Long(0);

            do {
                initialWeight = child.toFile().length();
                Thread.sleep(1000);
                finalWeight = child.toFile().length();
                isGrowing = initialWeight < finalWeight;

            } while(isGrowing);

            System.out.println("Finished creating file!");

        }
public boolean acquireExclusiveReadLock( ... ) throws Exception {
   LOG.trace("Waiting for exclusive read lock to file: {}", file);

   // the trick is to try to rename the file, if we can rename then we have exclusive read
   // since its a Generic file we cannot use java.nio to get a RW lock
   String newName = file.getFileName() + ".camelExclusiveReadLock";

   // make a copy as result and change its file name
   GenericFile<T> newFile = file.copyFrom(file);
   newFile.changeFileName(newName);
   StopWatch watch = new StopWatch();

   boolean exclusive = false;
   while (!exclusive) {
        // timeout check
        if (timeout > 0) {
            long delta = watch.taken();
            if (delta > timeout) {
                CamelLogger.log(LOG, readLockLoggingLevel,
                        "Cannot acquire read lock within " + timeout + " millis. Will skip the file: " + file);
                // we could not get the lock within the timeout period, so return false
                return false;
            }
        }

        exclusive = operations.renameFile(file.getAbsoluteFilePath(), newFile.getAbsoluteFilePath());
        if (exclusive) {
            LOG.trace("Acquired exclusive read lock to file: {}", file);
            // rename it back so we can read it
            operations.renameFile(newFile.getAbsoluteFilePath(), file.getAbsoluteFilePath());
        } else {
            boolean interrupted = sleep();
            if (interrupted) {
                // we were interrupted while sleeping, we are likely being shutdown so return false
                return false;
            }
        }
   }

   return true;
}
public void run()
{
    try
    {
        WatchKey key = myWatcher.take();
        while (key != null)
        {
            for (WatchEvent event : key.pollEvents())
            {
                if (FilenameUtils.isExtension(event.context().toString(), "filepart"))
                {
                    System.out.println("Inside the PartFile " + event.context().toString());
                } else
                {
                    System.out.println("Full file Copied " + event.context().toString());
                    //Do what ever you want to do with this files.
                }
            }
            key.reset();
            key = myWatcher.take();
        }
    } catch (InterruptedException e)
    {
        e.printStackTrace();
    }
}
[info] application - /var/www/webdav/.davfs.tmp39dee1 was created
[info] application - /var/www/webdav/document.docx was created
[info] application - /var/www/webdav/.davfs.tmp054fe9 was created
[info] application - /var/www/webdav/document.docx was created
[info] application - /var/www/webdav/.DAV/__db.document.docx was created 
val triggerFileName: String = triggerFileTempDir + orifinalFileName + "_" + Files.getLastModifiedTime(Paths.get(event.getFile.getName.getPath)).toMillis + "_0"

// creates trigger file in temporary directory
val triggerFile: File = new File(triggerFileName)
val isCreated: Boolean = triggerFile.createNewFile()

if (isCreated)
    println("Trigger created: " + triggerFileName)
else
    println("Error in creating trigger file: " + triggerFileName)
 val actualPath : String = "Original file directory here"
 val tempPath : String = "Trigger file directory here"
 val folder : File = new File(tempPath)    
 val listOfFiles = folder.listFiles()

for (i <- listOfFiles)
{

    // ActualFileName_LastModifiedTime_NumberOfTries
    val triggerFileName: String = i.getName
    val triggerFilePath: String = i.toString

    // extracting file info from trigger file name
    val fileInfo: Array[String] = triggerFileName.split("_", 3)
    // 0 -> Original file name, 1 -> last modified time, 2 -> number of tries

    val actualFileName: String = fileInfo(0)
    val actualFilePath: String = actualPath + actualFileName
    val modifiedTime: Long = fileInfo(1).toLong
    val numberOfTries: Int = fileStats(2).toInt

    val currentModifiedTime: Long = Files.getLastModifiedTime(Paths.get(actualFilePath)).toMillis
    val differenceInModifiedTimes: Long = currentModifiedTime - modifiedTime
    // checks if file has been copied completely(4 intervals of 5 mins each with no modification)
    if (differenceInModifiedTimes == 0 && numberOfTries == 3)
    {
        FileUtils.deleteQuietly(new File(triggerFilePath))
        println("Trigger file deleted. Original file completed : " + actualFilePath)
    }
    else
    {
        var newTriggerFileName: String = null
        if (differenceInModifiedTimes == 0)
        {
            // updates numberOfTries by 1
            newTriggerFileName = actualFileName + "_" + modifiedTime + "_" + (numberOfTries + 1)
        }
        else
        {
            // updates modified timestamp and resets numberOfTries to 0
            newTriggerFileName = actualFileName + "_" + currentModifiedTime + "_" + 0
        }

        // renames trigger file
        new File(triggerFilePath).renameTo(new File(tempPath + newTriggerFileName))
        println("Trigger file renamed: " + triggerFileName + " -> " + newTriggerFileName)
    }    
}