Project1

标题: Ruby中的File模块的exists?方法不支持中文? [打印本页]

作者: 逸豫    时间: 2010-7-10 21:51
标题: Ruby中的File模块的exists?方法不支持中文?
RT,中文会直接返回false,英文就不会……求解……
另:不是编码问题,已经把文件名字符串编码转换为ANSI一样没用……
作者: 后知后觉    时间: 2010-7-10 21:55
本帖最后由 后知后觉 于 2010-7-10 21:58 编辑

默认的不支持中文
  1. PathFileExists = Win32API.new("shlwapi", "PathFileExistsW", "P", "I")
  2. MultiByteToWideChar = Win32API.new("kernel32", "MultiByteToWideChar", "ILPIPI", "I")
  3. def FileTest.exists?(filename)
  4.   len = MultiByteToWideChar.call(65001, 0, filename, -1, 0, 0) << 1
  5.   buf = " " * len
  6.   MultiByteToWideChar.call(65001, 0, filename, -1, buf, len)
  7.   return PathFileExists.call(buf) == 0 ? false : true
  8. end
复制代码

作者: 神思    时间: 2010-7-10 21:56
最简单的。。
open之...异常之....{:nm_7:}
作者: 紫苏    时间: 2010-7-11 07:58
本帖最后由 紫苏 于 2010-7-11 07:59 编辑

确实比较诡异,刚看了下源码,没有发现任何改变了文件名字符串的地方,那么 File.exists? 按理说是应该使用当前用户 locale 的代码页的,所以可以用 ANSI 的字符串,但把 ANSI 编码的文件名传给 PathFileExistsA 和 FindFirstFileA 就可以,而 File.exists? 却失败。本来怀疑是由于底层调用了 POSIX 标准的 I/O 函数 stat 而导致的(编码?)问题,但我直接用 Win32 环境下的 CRT 里的 stat 来测试了下,又没有问题,而且 File.open 同样用了 POSIX 标准的 fdopen,也并没有这个问题,难道是由于不同的实现?……|| 等待高手释疑,这里把 File.exists? 方法的例行程序路由贴出来供有兴趣的人研究

FileTest.exists? 的 C 原型是 test_e;

  1. define_filetest_function("exist?", test_e, 1);
  2. define_filetest_function("exists?", test_e, 1); /* temporary */
复制代码
test_e 调用 rb_stat 函数并传递 filename,如果 rb_stat 的返回值小于 1 则返回 false(文件不存在);
test_e: http://ruby-doc.org/doxygen/1.8.4/file_8c-source.html#l01101

rb_stat 调用 StringValueCStr(filename),实则是一个调用了 rb_string_value_cstr(filename) 的宏,将 Ruby 字符串转换为 C 字符串 cstr;
rb_stat:http://ruby-doc.org/doxygen/1.8.4/file_8c-source.html#l00647
StringValueCStr:http://ruby-doc.org/doxygen/1.8.4/ruby_8h-source.html#l00245
rb_string_value_str:http://ruby-doc.org/doxygen/1.8.4/string_8c-source.html#l00565

rb_stat 调用 stat 获取文件状态,stat 返回;rb_stat 返回 stat 返回的值;test_e 返回 rb_stat 返回的值
作者: IamI    时间: 2010-7-11 08:34
我囧了……
  1. a = Dir["*.*"]
  2. p a                           =>最后一个是"你好.txt"
  3. p File.exists?(a.last)   =>false
复制代码

作者: 小幽的马甲    时间: 2010-7-11 08:56
真神奇……File.delete或者rename之类的都能支持中文,而FileTest.exist?却不行= =
作者: 紫苏    时间: 2010-7-11 12:07
真神奇……File.delete或者rename之类的都能支持中文,而FileTest.exist?却不行= =
小幽的马甲 发表于 2010-7-11 08:56


刚又看了下,delete 用的是 unlink,rename 用的就是 rename,都是 POSIX 标准的函数,不知道为什么用到 stat 的时候就有问题……可能在路由过程中有什么我没看到,强烈建议大家去瞅瞅源代码,帮楼主解决问题的同时还能提高代码阅读能力 XD
作者: 谢谢合作    时间: 2010-7-11 12:53
。。。
在游戏目录新建一个文件:

然后再用脚本测试:
  1. p FileTest.exist?("这是中文.txt")  #==>true

  2. exit
复制代码
...

To 5楼,
用你那脚本,在我的环境里,是TRUE、、、
作者: 紫苏    时间: 2010-7-11 13:01
IamI  发表于 35 秒前
请注意此乃XP讨论区XP提问…… 经测试VX可通过XP依旧为假……大家去翻Ruby版本的更新目录吧……

呃,这话倒是提醒我了,VX 没错的话就不是 Ruby 的问题,而是 RMXP 的问题了(莫妮卡你在哪……) 0.- 因为根据 VX 的 about 对话框信息来看,VX 的 Ruby 版本仍然是 1.8.1
作者: 谢谢合作    时间: 2010-7-11 13:09
ok,我想好了、、

  1. d_s = "" # 这里改搜索目录,别忘了加 /

  2. dir_array = Dir["#{d_s}*.*"]

  3. if dir_array.include?("这是中文.txt")
  4.   p "存在该文件、、、"
  5. end

  6. exit
复制代码





欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1