作为 Upstart 服务启动时无法读取 UTF-8 文件名

2022-09-03 14:07:11

我的 Java 程序以递归方式读取目录的内容。这是一个示例树(请注意非 ASCII 字符):

./sviluppo
./sviluppo/ciaò
./sviluppo/ciaò/subdir
./sviluppo/pippo
./sviluppo/pippo/prova2.txt <-file
./sviluppo/così

该程序作为Upstart服务启动,其配置文件名为like/init/myservice.conf

description "Private Service"
author "AD"
start on runlevel [2345]
stop on runlevel [! 2345]
exec java -jar /home/mainFind.jar >> /tmp/log.txt

当我启动服务时:

root@mdr:/tmp#  service myservice start
myservice start/running, process 15344

它不会记录名称中包含非 ASCII 字符的文件名:

root@mdr:/tmp#  cat /tmp/log.txt
Found dir: /mnt/sviluppo/pippo

相反,当我运行命令(作为root,以模仿当它作为服务启动时发生的情况)时,它可以正常工作,有和没有:exec

root@mdr:/tmp# java -jar /home/mainFind.jar  >> /tmp/log.txt
root@mdr:/tmp# exec java -jar /home/mainFind.jar  >> /tmp/log.txt

root@mdr:/tmp#  cat /tmp/log.txt
Found dir: /mnt/sviluppo/ciaò
Found dir: /mnt/sviluppo/ciaò/subdir
Found dir: /mnt/sviluppo/pippo
Found dir: /mnt/sviluppo/così

为什么由同一用户运行的同一程序在Upstart服务中不起作用,但在从命令行运行时正确处理所有文件名?这是Java代码

public static void aggiungiFileDir(File f){
  File[] lista= f.listFiles();
  for(int i=0;i<lista.length;i++){
    if(lista[i].isDirectory()){
      System.out.println("Found dir: "+lista[i]); 
    }
  }
}

其中形式参数是根目录。该函数将在每个子目录上以递归方式调用。f

编辑2:帖子ls

root@mdr:/tmp# ls -al /mnt/sviluppo
totale 20
drwx------ 5 root root 4096 nov 15 15:10 .
drwxr-xr-x 7 root root 4096 nov  9 10:43 ..
drwxr-xr-x 2 root root 4096 nov 15 15:10 ciaò
drwxr-xr-x 2 root root 4096 nov 15 11:23 così
drwxr-xr-x 2 root root 4096 nov 15 17:57 pippo

答案 1

Java 使用本机调用来列出目录的内容。基础 C 运行时依赖于区域设置概念,从文件系统存储的字节 blob 生成 Java。。String

当您从 shell 执行 Java 程序时(无论是作为特权用户还是非特权用户),它都会携带一个由变量组成的环境。读取该变量以将字节流转码为 Java 字符串,默认情况下,在 Ubuntu 上,它与 UTF-8 编码相关联。LANG

请注意,进程不需要从任何 shell 运行,但从代码来看,Upstart 似乎足够聪明,可以理解配置文件中的命令何时打算从 shell 执行。因此,假设 JVM 是通过 shell 调用的,问题在于变量未设置,因此 C 运行时假定一个默认字符集,而该字符集恰好不是 UTF-8。解决方案位于“新贵”节中:LANG

description "List UTF-8 encoded filenames"
author "Raffaele Sgarro"
env LANG=en_US.UTF-8
script
  cd /workspace
  java -jar list.jar test > log.txt
end script

我用作语言环境,但任何UTF-8支持的一个都可以。测试的来源en_US.UTF-8list.jar

public static void main(String[] args) {
    for (File file : new File(args[0]).listFiles()) {
        System.out.println(file.getName());
    }
}

该目录包含诸如 等文件名。现在,您可以移动到数据库部件;)/workspace/testàààèèè


答案 2

将其添加到 /etc/init.d/script 为我修复了这个问题(我从 /etc/init.d/tomcat7 复制了它):

# Make sure script is started with system locale
if [ -r /etc/default/locale ]; then
    . /etc/default/locale
    export LANG
fi

我的机器上 /etc/default/locale 的内容:

LANGUAGE=en_US:en
LANG=en_US.UTF-8

推荐