• Java Process:另一个程序正在使用此文件,进程无法访问


    最近处理奇怪的问题时,犯了个低级错误,浪费了不少时间,甚至都看了 jdk 底层的 c 代码。

    下面这段测试代码是在 Windows 环境运行的(Mac和linux换成 /bin/sh,-c 后没有问题),你能发现错误在哪里吗?

    @Test
    public void test() throws Exception {
        String fileName = "out.log";
        File file = new File(fileName);
        Process process = new ProcessBuilder(getCommands(fileName)).redirectOutput(file).start();
        if(process.isAlive()) {
            process.waitFor();
        }
        BufferedReader readStderr = new BufferedReader(new InputStreamReader(process.getErrorStream(), "gbk"));
        String line;
        while((line = readStderr.readLine()) != null) {
            System.err.println(line);
        }
        readStderr.close();
    }
    
    public List<String> getCommands(String fileName) {
        String os = System.getProperty("os.name");
        if (os.toLowerCase().startsWith("win")) {
            return Arrays.asList("cmd", "/c", "echo", "hello world", ">", fileName);
        } else {
            return Arrays.asList("/bin/sh", "-c", "echo", "hello world", ">", fileName);
        }
    }
    

    Windows环境执行会提示错误 另一个程序正在使用此文件,进程无法访问,错误已经很直接了,但是由于在 Mac 和 Linux 环境没有问题,因此觉得类似的代码在 Windows 上也不存在问题。

    debug过程中,修改 getCommands 中的 fileName 时也能成功,有时候修改就不能成功,有时候文件名短的时候能经常性的成功,偶尔会有长文件名的时候也能成功。

    错误也很明显了吧?

    仍然在迷糊中…

    这里新建的文件名,为什么会被占用呢?Windows为什么不把被占用的文件名提示出来?

    想看看C代码部分能不能提供有效的信息…

    JNIEXPORT jlong JNICALL
    Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
                                      jstring cmd,
                                      jstring envBlock,
                                      jstring dir,
                                      jlongArray stdHandles,
                                      jboolean redirectErrorStream)
    {
        jlong ret = 0;
        if (cmd != NULL && stdHandles != NULL) {
            const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);
            if (pcmd != NULL) {
                const jchar *penvBlock = (envBlock != NULL)
                    ? (*env)->GetStringChars(env, envBlock, NULL)
                    : NULL;
                if (!(*env)->ExceptionCheck(env)) {
                    const jchar *pdir = (dir != NULL)
                        ? (*env)->GetStringChars(env, dir, NULL)
                        : NULL;
                    if (!(*env)->ExceptionCheck(env)) {
                        jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
                        if (handles != NULL) {
                            ret = processCreate(
                                env,
                                pcmd,
                                penvBlock,
                                pdir,
                                handles,
                                redirectErrorStream);
                            (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
                        }
                        if (pdir != NULL)
                            (*env)->ReleaseStringChars(env, dir, pdir);
                    }
                    if (penvBlock != NULL)
                        (*env)->ReleaseStringChars(env, envBlock, penvBlock);
                }
                (*env)->ReleaseStringChars(env, cmd, pcmd);
            }
        }
        return ret;
    }
    

    太长了…跳过…

    由于代码不是我写的,所以处理过程中,没有仔细的看过完整的 Process 创建过程,有一瞬间,突然看到了问题的关键:

    redirectOutput(file)
    //和
    ">", fileName
    

    上面这个方法已经把输出重定向到 file 了,new File(fileName) 时和命令当前执行的路径是一样的,通过 > fileName 时也是重定向到 fileName 中,所以 另一个程序正在使用此文件,进程无法访问,另一个程序竟然就是自己。

    将上面两种方式随便去掉哪一个都可以正常运行。

    你在看本文的过程中,有没有更早的发现问题呢?

    当 Windows 提示你的操作遇到 “另一个程序正在使用此文件,进程无法访问” 时,这个文件大概率就是你操作的文件,如果找不到其他被使用的地方,可能就是你自己重复使用了同一个文件。

  • 相关阅读:
    循环树和checkbox 相关选中处理
    Java版分布式微服务云开发架构 Spring Cloud+Spring Boot+Mybatis 电子招标采购系统功能清单
    cesium加载倾斜影像数据(模拟雨、雪、雾、无人机飞行、测距、箭头标绘、电子围栏等)
    APK 逆向工程 - 解析 apk 基本信息和方法调用图
    竞赛 深度学习卫星遥感图像检测与识别 -opencv python 目标检测
    【数据结构】从链表到LinkedList类
    C++ UDP通信
    吃瓜教程-模型的评估与选择
    当Python遇到分形数学魔法 --> 树叶
    Decimal.ToString()堆栈溢出异常
  • 原文地址:https://blog.csdn.net/isea533/article/details/127096031