(Java)更改的目录(通过bash脚本)未反映在folder.listfiles中

时间:2011-07-18 20:51:59

标签: java bash

我从我的Java程序运行一个bash脚本,它接收一大块数据,操作它并将其拆分。

这不是bash脚本是否有效的问题 - 我可以在目录中看到拆分文件。

在data /

中说原始文件是“bigFile”

然后

    try
    {
        Process proc = Runtime.getRuntime().exec("bash " + SCRIPT_DIR + "/" + SPLIT_SCRIPT_NAME + " " + args[_MESSAGES_PER_UPLOAD_] + " " + args[_MAXIMUM_MESSAGES_PER_FEED_] + " " + (60000*Integer.parseInt(args[_DURATION_BEFORE_EACH_UPLOAD_IN_MINUTES_])/Integer.parseInt(args[_DURATION_OF_EACH_FEED_IN_MILLISECONDS_])));
        proc.waitFor();
    }
    catch(IOException e) { error(e); }

    String fileNames;
    File folder = new File(DATA_DIR);

    File[] filesToUpload = folder.listFiles();

    for (int i = 0; i < filesToUpload.length; ++i)
        if (filesToUpload[i].isFile()) 
        {
            fileNames = filesToUpload[i].getName();
            System.out.println(fileNames);
        }

将打印bigFile,而不是......

$ ls data /

dataChunk_00000 dataChunk_00001 dataChunk_00002 dataChunk_00003 dataChunk_00004 dataChunk_00005 dataChunk_00006 dataChunk_00007 dataChunk_00008 dataChunk_00009 dataChunk_00010 dataChunk_00011 dataChunk_00012 dataChunk_00013 dataChunk_00014 dataChunk_00015 dataChunk_00016 dataChunk_00017 dataChunk_00018 dataChunk_00019 dataChunk_00020 dataChunk_00021 dataChunk_00022 dataChunk_00023 dataChunk_00024 dataChunk_00025 dataChunk_00026 dataChunk_00027

应该如此。我猜这是编译器优化或其他什么。

编辑:如果有人可以向我解释为什么proc.waitFor()不起作用和/或更好的解决方法,我会非常感激。

5 个答案:

答案 0 :(得分:3)

这个问题不是编译器优化或类似的东西。

因为你在前面用“bash”调用你的脚本。这会导致进程fork - 所以你的bash命令会立即成功返回,但你的脚本会继续在后台运行并终止。

proc.waitFor()没有什么可以等待的,java程序的其余部分在文件被“拆分”之前执行。

答案 1 :(得分:2)

您无法使用java更改目录。 如果你想“模拟”它,你需要做的就是设置属性“user.dir”。

答案 2 :(得分:1)

我猜你的bash脚本正在从它自己的进程/线程异步执行操作。这意味着脚本在工作完成之前完成执行。这仍将通过waitFor()检查并继续执行代码。

编辑: Kal的答案更清楚地解释了这一点,并且首先发布了。问题在于您使用bash命令来执行脚本。

答案 3 :(得分:0)

我怀疑你的论据并没有全部传递给你的剧本。

将所有参数放在ArrayList实例中,将实例传递给ProcessBuilder,然后在构建器实例上调用start方法,该方法返回调用waitFor的proc。

这里有Scala代码示例,用于显示我的意思(如果您真的感兴趣,我可以将其移植到Java中;):

import java.lang.{ Process => JProcess, ProcessBuilder => JProcessBuilder }
import java.util.{ArrayList => JArrayList, List => JList, Map => JMap}
import java.io.{InputStreamReader, BufferedReader}

def call(args: String*) = {
    val command: JList[String] = new JArrayList[String]()

    args.foreach {arg =>
      command.add(arg)
    }

    //log.debug("argument list: %s", command.toString)

    val builder = new JProcessBuilder(command)

    val proc: JProcess = builder.start()
    proc.waitFor()

    val read = new BufferedReader(new InputStreamReader(proc.getInputStream()));

    val sb: StringBuffer = new StringBuffer()
    while(read.ready()) {
      sb.append(read.readLine)
    }

    // sb now has the output of the called process...

    val exitValue: Int = proc.exitValue

    // http://stuffthathappens.com/blog/2007/11/28/crash-boom-too-many-open-files/
    read.close
    proc.destroy

    (exitValue, sb.toString) // return it
}

REPL中的示例调用:

scala> call("date")
res156: (Int, java.lang.String) = (0,Mon 18 Jul 2011 22:29:58 BST)

答案 4 :(得分:0)

此计划有许多错误的假设:

  1. 每次执行'exec'时,您都会使用自己的环境,当前目录等来分叉新进程。当前目录的任何更改都将是该进程的本地更改,并且不会影响父进程(您的Java进程) 。换句话说,没有办法在子进程中使用命令更改应用程序的当前路径,也没有Java API - 如果你真的需要它,你必须使用本机调用。
  2. Unix上的'cd'命令是一个真正的命令,你不需要shell来运行它(不像Windows)。
  3. 当你分叉一个进程时,你需要确保你耗尽了stdout和stderr,否则它会在OS缓冲区满了时阻塞(参见下一篇)
  4. Process.waitFor()有效。总是。
  5. 解决问题的更好方法是仔细阅读File API,并尽可能使用绝对路径。当你在shell中时,'当前目录'是非常有用的东西,但是对于应用程序来说它最终会更加混乱,所以越早将它解析为绝对路径 - 越好。