英文:
Node.JS on IBMi / OS400: filename with accents non accessible
问题
我有一个NodeJs(14和18)服务,它可以列出和读取本地文件系统上的文件,在IBMi或AS/400上...
我使用以下方式:
- 用于列出我的目录中所有文件的
await fsPromises.readdir(mydir)
- 用于读取内容的
await fsPromises.readFile(filename)
对于没有重音符号的文件名,没有问题...
但是,当文件名中有一些法语重音符号时,我遇到了几个问题:
-
readdir(mydir)
返回 name_��.png 而不是 name_éè.png ... 但我通过使用编码参数来解决了这个问题,readdir(mydir, {encoding: 'binary'})
返回了正确的文件名! -
调用
await fsPromises.readFile('name_éè.png')
或await fsPromises.readFile('name_éè.png', {encoding: 'binary'})
会导致访问异常: name_��.png: ENOENT: 找不到文件或目录
似乎 "encoding" 选项只适用于结果,而不适用于文件名参数。这个问题似乎在Windows机器上不存在,但似乎特定于AS/400。
上下文:
软件版本: 在NodeJS v 14.21.3上测试,OS400 V7R3
通常是通过包含以下命令的CL启动的
CMD(QSH CMD(&CMD)) JOB(&JOB) JOBQ(QUSRNOMAX) CCSID(1147) SPLFACN(*DETACH)
其中 &CMD 是SH脚本的路径( node app.js &
)
而 &JOB 是服务的名称...
我也测试了不带CCSID(1147)参数的情况,但是我遇到了同样的问题...(最后,这并不代表什么,因为它是系统默认设置...)
有没有什么办法解决这个问题?
谢谢
英文:
I have a NodeJs (14 & 18) service which list and read files from the local filesystem, on IBMi or AS/400...
I use:
await fsPromises.readdir(mydir)
for to list all files of my directoryawait fsPromises.readFile(filename)
for to read the content...
For filenames without accent, there is no problem...
But, when there are some french accents, I have several problems:
-
readdir(mydir)
return name_��.png instead of name_éè.png ... But I resolve this first problem with the encoding parameter, andreaddir(mydir, {encoding: 'binary'})
return the good name ! -
calling
await fsPromises.readFile('name_éè.png')
orawait fsPromises.readFile('name_éè.png', {encoding: 'binary'})
causes an access exception: name_��.png: ENOENT: no such file or directory
It seems that the "encoding" option only applies to the result, and not to the filename parameter. This problem does not seem to exist on a Windows machine, but seems specific to AS/400.
Context:
Software version: tested with NodeJS v 14.21.3, and OS400 V7R3
Usually it is started via a CL which contains the command
CMD(QSH CMD(&CMD)) JOB(&JOB) JOBQ(QUSRNOMAX) CCSID(1147) SPLFACN(*DETACH)
where &CMD is the path of the SH script ( node app.js &
)
and &JOB is the service's name...
I also tested it whithout the CCSID(1147) parameter, but I had the same problem... (finally, it doesn't mean anything because it's the system default...)
Any idea to resolve this ?
Thanks
答案1
得分: 1
一般来说,对于运行PASE程序,QSH是一个不好的选择。
将QSH
视为IBM本机的“类Unix” shell仿真。可用的命令都是实际*PGM对象的别名。
在处理PASE工具和特定的开源软件包时,最好使用真正的Unix/Linux shell。对于交互式使用,最好从客户端PC通过SSH连接。如果您绝对没有选择使用5250,那么QP2TERM
比QSH
更好。
对于启动批处理作业,即后台服务,PASE shell QP2SHELL
和 QP2SHELL2
都是可能的选项。请确保阅读并理解这些命令的注释。
然而,处理IBM i上的开源服务的绝佳方式是通过开源的Service Commander。
最后,如果以上方法都没有帮助,您可以尝试联系其他IBM i的开源社区。
-
IBM i开源Ryver聊天(必须首先加入此链接)
-
IBM i社区Slack(必须首先加入此链接)
-
Twitter上的#IBMiOSS标签9
-
Jesse Gorzinski的个人Twitter10
英文:
Generally speaking, QSH is a bad choice for running PASE programs.
Think of QSH
as a IBM native "Unix like" shell emulmation. The commands available are alias to actual *PGM objects.
When dealing with PASE tools and open-source packages specifically, a real Unix/Linux shell is preferred. For interactive usage, SSH from your client PC is preferred. If you absolutely have no choice to use 5250, then QP2TERM
is a better choice than QSH
.
For starting a batch job aka background service, the PASE shells QP2SHELL
and QP2SHELL2
are possible options. Be sure to read and understand the notes for those commands.
However, the absolute best way to handle open-source services on the IBM i is via the open-source Service Commander
Lastly, if non of the above helps, you may want to reach out to other IBM i open source communities.
- IBM i Open Source Chat on Ryver (must first join at this link)
- IBM i Community Slack (must first join at this link)
- IBM Community pages for IBM i
- IBMiOSS LinkedIn group
- #IBMiOSS hashtag on Twitter
- Jesse Gorzinski’s personal Twitter
答案2
得分: 0
我最终解决了我的问题:这是Node和AS/400作业环境之间字符编码差异的问题:
-
在Node中,所有字符串都是utf8编码的。
-
但是OS400与执行环境的CCSID(在我的情况下是1147)相关联,因此utf8文件的名称在传递给"fs"原语或"fsPromises"时必须尽快转换...
具体来说:
- 我创建了一个转换函数(因为我的Node服务也可以在Windows或Linux机器上运行,...)
const os = require('os');
let ENCODING_TYPE = 'utf8';
if (os.type() == "OS400"){
ENCODING_TYPE = 'binary'; // 对于CCSID 1147
}
function convertFilenameCharset(filename){
if (os.type() != "OS400"){
return filename;
}
const res = Buffer.from(filename, 'binary'); // 返回Buffer对象中的文件名!
return res;
}
- 我在"fs" API调用中使用它...
await fsPromises.unlink(convertFilenameCharset(fullfilepath));
await fsPromises.rename(workfilepath, convertFilenameCharset(fullfilepath));
let data = await fsPromises.readFile(convertFilenameCharset(fullFilePath));
要读取目录中的元素列表,结果也必须重新编码:
let files = await fsPromises.readdir(convertFilenameCharset(abspath), {encoding: ENCODING_TYPE});
注意:
对于某些API,例如await Jimp.read(convertFilenameCharset(filepath))
,它无法运行,因为它们不支持像"fs" API那样的Buffer参数:在这些情况下,我使用normalize-diacritics模块生成没有重音符号的新文件名,并对文件源进行工作副本...
英文:
I finally solved my problem: it's a problem of character encoding difference between Node and the AS/400 job environment:
-
in Node, all strings are utf8 encoded
-
but OS400 is linked to the CCSID (1147 in my case) of the execution environment (of the job, of the user profile, etc.) and therefore the names of utf8 files must be converted as soon as they are transmitted to the "fs" primitives or "fsPromises"...
Concretely:
- I made a conversion function (because my Node service can also run on Windows or Linux machines,...)
const os = require('os');
let ENCODING_TYPE = 'utf8';
if (os.type() == "OS400"){
ENCODING_TYPE = 'binary'; // for CCSID 1147
}
function convertFilenameCharset(filename){
if (os.type() != "OS400"){
return filename;
}
const res = Buffer.from(filename, 'binary'); // return the filename in a Buffer object !
return res;
}
- I use it in "fs" API calls...
await fsPromises.unlink(convertFilenameCharset(fullfilepath));
await fsPromises.rename(workfilepath, convertFilenameCharset(fullfilepath));
let data = await fsPromises.readFile(convertFilenameCharset(fullFilePath));
For read the list of elements of a directory, the result must also be re encoded:
let files = await fsPromises.readdir(convertFilenameCharset(abspath), {encoding: ENCODING_TYPE});
NOTE:
it doesn't run for some API like await Jimp.read(convertFilenameCharset(filepath))
because they don't support Buffer parameter like the "fs" API: in those cases, I use the normalize-diacritics module to generate a new filename without accents, and I do a work copy of the file source...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论