InstallScript GetLine()无法读取文本文件,其中包含命令提示符下的结果 [英] InstallScript GetLine() can not read text file contains result from command prompt

查看:109
本文介绍了InstallScript GetLine()无法读取文本文件,其中包含命令提示符下的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的安装需要检查cmd.exe中的命令结果.因此,我将命令的结果重定向到文本文件,然后尝试读取文件以获取结果,如下所示:

 // send command to cmd to execute and redirect the result to a text file

// try to read the file
szDir = "D:\\";
szFileName = "MyFile.txt";

if Is(FILEEXISTS, szDir ^ szFileName) then
    listID = ListCreate(STRINGLIST);
    if listID != LIST_NULL then
        if OpenFIleMode(FILE_MODE_NORMAL) = 0 then
            if OpenFile(nFileHandle, szDir, szFileName) = 0 then

                // I run into problem here
                while (GetLine(nFileHandle, szCurLine) = 0 )
                    ListAddString(listID, szCurLine, AFTER);
                endwhile;
                CloseFile(nFileHandle);

            endif;
        endif;
    endif;
endif;
 

问题是执行命令提示符并将结果重定向到MyFile.txt之后,我可以设置打开文件模式,打开文件,但无法将任何文本读入列表. ListReadFromFile()没有帮助.如果我打开文件,然后手动编辑并保存,则脚本可以正常工作.

调试后,我发现GetLine()返回错误代码(-1),这意味着文件指针必须位于文件末尾或其他错误.但是,FILE_MODE_NORMAL将文件设置为只读,并在文件开始时设置文件指针.

我可能做错了什么?这与文件的读/写访问有关吗?我尝试了此命令但没有结果:

icacls D:\MyFile.txt /grant Administrator:(R,W)

我正在使用IstallShield 2018和Windows 10 64位btw.非常感谢您的帮助.

我怀疑编码并尝试了一些操作:

  1. 运行"wslconfig/l"后,在Notepad ++中打开的MyFile.txt的内容没有编码,但仍然显示正常且可读.我试图将内容转换为UTF-8,但没有用.

  2. 如果我向文件中添加了一些内容(回显此行,请附加>> MyFile.txt),则编码更改为UTF-8,但步骤1中的内容也更改了.在每个字符之间添加NULL(\ 0),甚至排斥换行符.也许这就是为什么GetLine()无法读取文件的原因.

  3. 解决方法:在步骤1之后,我运行查找"my_desired_content" MyFile.txt> TempFile.txt并读取TempFile.txt(以UTF-8编码).

我的最终目标是检查"my_desired_content"是否出现在"wslconfig/l"的结果中,所以这很好.但是,我不明白的是MyFile.txt和TempFile.txt都是通过cmd命令创建的,但是编码方式不同?

解决方案

问题是由于文件的内容所致.假设这是由链接的问题生成的文件,则可以在十六进制编辑器中检查其内容,以发现以下事实:

  • 其内容以UTF-16(LE)编码,而没有BOM
  • 其换行符编码为CR或CR CR,而不是CR LF

我认为换行符比文本编码更重要,但是事实证明我倒行了.如果我分别更改所有这些内容,则GetLine对于CR,CR CR或CR LF似乎都能正常运行,但是仅在存在BOM时才处理UTF-16. (也就是说,在十六进制编辑器中,文件以FF FE 57 00开头,而不是以字符W开头的文件为57 00.)

对于解决此问题的最佳方法,我有点不知所措.如果您面临挑战,则可以使用FILE_MODE_BINARYREADONLY读取文件,并可以使用有关文件内容的额外知识来确保正确解释其编码.请注意,对于大多数UTF-16,您可以通过以下方式组合两个字节来创建单个代码单元:

szResult[i] = (nHigh << 8) + nLow;

其中nHighnLow可能是szBuffer[2*i + 1]szBuffer[2*i]之类的值,假设您通过调用ReadBytes填充了STRING szBuffer.

其他未经验证的想法包括:以二进制格式编辑该文件以确保存在BOM(FF FE);找出确保该文件最初是由BOM创建的方法;找出以另一种编码创建该文件的方法;找到另一个命令您可以调用以修复"文件,或向供应商(我的老板)提出请求,并希望开发团队进行一些更改以更好地处理这种情况.


这是一个更简单的解决方法.如果可以安全地假定该命令将不带签名地附加UTF-16字符,则可以将此输出附加到仅具有签名的文件中.您如何获得这样的文件?

  • 您可以在开发环境中仅使用BOM表创建文件,然后将其添加到支持文件中.如果您需要多次使用,请先将其复制.
  • 您可以使用代码创建它.只需调用以下内容即可(为清楚起见,省略了错误检查)

    OpenFileMode(FILE_MODE_APPEND_UNICODE);
    CreateFile(nFileHandle, szDir, szFileName);
    CloseFile(nFileHandle);
    

    并且如果szDir ^ szFileName不存在,则它将成为仅具有UTF-16签名的文件.

假设此文件名为sig.txt,则可以调用以下命令 wslconfig /l >> sig.txt写入该文件.注意追加的>>的两倍.生成的文件将包含您提前创建的Unicode签名,以及从wslconfig输出的Unicode数据,GetLine应该正确地解释事物.

此处最大的问题是,此代码围绕wslconfig的行为进行了硬编码,并且该行为可能随时发生变化.这就是Christopher暗示推荐API的原因,我完全同意.同时,您可以尝试通过在cmd /U中调用它来使其更加健壮(但是我对此的理解或保证充其量是模糊的),或者尝试使用原始方法,然后使用BOM. /p>

My Installation needs to check the result of a command from cmd.exe. Thus, I redirect the result of the command to a text file and then try to read the file to get the result as follows:

// send command to cmd to execute and redirect the result to a text file

// try to read the file
szDir = "D:\\";
szFileName = "MyFile.txt";

if Is(FILEEXISTS, szDir ^ szFileName) then
    listID = ListCreate(STRINGLIST);
    if listID != LIST_NULL then
        if OpenFIleMode(FILE_MODE_NORMAL) = 0 then
            if OpenFile(nFileHandle, szDir, szFileName) = 0 then

                // I run into problem here
                while (GetLine(nFileHandle, szCurLine) = 0 )
                    ListAddString(listID, szCurLine, AFTER);
                endwhile;
                CloseFile(nFileHandle);

            endif;
        endif;
    endif;
endif;

The problem is that right after the command prompt is executed and the result is redirected to MyFile.txt, I can set open file mode, open the file but I can not read any text into my list. ListReadFromFile() does not helps. If I open the file, edit and save it manually, my script works.

After debugging, I figured that GetLine() returns an error code (-1) which means the file pointer must be at the end of file or other errors. However, FILE_MODE_NORMAL sets the file as read only and SET THE FILE POINTER AT THE BEGINNING OF THE FILE.

What did I possibly do wrong? Is this something to do with read/write access of the file? I tried this command without result:

icacls D:\MyFile.txt /grant Administrator:(R,W)

I am using IstallShield 2018 and Windows 10 64-bit btw. Your help is much appreciated.

EDIT 1: I suspected the encoding and tried a few things:

  1. After running "wslconfig /l", the content of MyFile.txt opened in Notepad++ is without an encoding, but still appeared normal and readable. I tried to converted the content to UTF-8 but it did not work.

  2. If I add something to the file (echo This line is appended >> MyFile.txt), the encoding changed to UTF-8, but the content in step 1 is changeed also. NULL (\0) is added to between every character and even repelace new line character. Maybe this is why GetLine() failed to read the file.

  3. Work around: after step 1, I run "find "my_desired_content" MyFile.txt" > TempFile.txt and read TempFile.txt (which is encoded in UTF-8).

My ultimate goal is to check if "my_desired_content" apeears in the result of "wslconfig /l" so this is fine. However, what I don't understand is that both MyFile.txt and TempFile.txt are created from cmd command but they are encoded differently?

解决方案

The problem is due to the contents of the file. Assuming this is the file generated by your linked question, you can examine its contents in a hex editor to find out the following facts:

  • Its contents are encoded in UTF-16 (LE) without a BOM
  • Its newlines are encoded as CR or CR CR instead of CR LF

I thought the newlines would be more important than the text encoding, but it turns out I had it backwards. If I change each of these things independently, GetLine seems to function correctly for either CR, CR CR, or CR LF, but only handles UTF-16 when the BOM is present. (That is, in a hex editor, the file starts with FF FE 57 00 instead of 57 00 for a file starting with the character W.)

I'm at a bit of a loss for the best way to address this. If you're up for a challenge, you could read the file with FILE_MODE_BINARYREADONLY, and can use your extra knowledge about what should be in the file to ensure you interpret its encoding correctly. Note that for most of UTF-16, you can create a single code unit by combining two bytes in the following manner:

szResult[i] = (nHigh << 8) + nLow;

where nHigh and nLow are probably values like szBuffer[2*i + 1] and szBuffer[2*i], assuming you filled a STRING szBuffer by calling ReadBytes.

Other unproven ideas include editing it in binary to ensure the BOM (FF FE) is present, figuring out ways to ensure the file is originally created with the BOM, figuring out ways to create it in an alternate encoding, finding another command you can invoke to "fix" the file, or lodging a request with the vendor (my employer) and hoping the development team changes something to better handle this case.


Here's an easier workaround. If you can safely assume that the command will append UTF-16 characters without a signature, you can append this output to a file that has just a signature. How do you get such a file?

  • You could create a file with just the BOM in your development environment, and add it to your Support Files. If you need to use it multiple times, copy it around first.
  • You could create it with code. Just call the following (error checking omitted for clarity)

    OpenFileMode(FILE_MODE_APPEND_UNICODE);
    CreateFile(nFileHandle, szDir, szFileName);
    CloseFile(nFileHandle);
    

    and if szDir ^ szFileName didn't exist, it will now be a file with just the UTF-16 signature.

Assuming this file is called sig.txt, you can then invoke the command wslconfig /l >> sig.txt to write to that file. Note the doubled >> for append. The resulting file will include the Unicode signature you created ahead of time, plus the Unicode data output from wslconfig, and GetLine should interpret things correctly.

The biggest problem here is that this hardcodes around the behavior of wslconfig, and that behavior may change at any point. This is why Christopher alludes to recommending an API, and I agree completely. In the mean time, You could try to make this more robust by invoking it in a cmd /U (but my understanding of what that does or guarantees is fuzzy at best), or by trying the original way and then with the BOM.

这篇关于InstallScript GetLine()无法读取文本文件,其中包含命令提示符下的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆