Неожиданные символы в файле при использовании System .IO.FileStream.writeByte() из Powershell

#.net #powershell #file-writing

#.net #powershell #запись в файл

Вопрос:

Пожалуйста, рассмотрите следующий сценарий Powershell:

 Out-File -FilePath "c:batchvsstest.txt" -NoNewline -InputObject "0"

$Stream = [System.IO.File]::Open("c:batchvsstest.txt",
                                 [System.IO.FileMode]::Open,
                                 [System.IO.FileAccess]::Write,
                                 [System.IO.FileShare]::ReadWrite)
$Stream.WriteByte(49)

$Stream.Dispose()
  

После выполнения сценария файл c:batchvsstest.txt содержит неожиданные символы. Он содержит следующие 4 байта (в шестнадцатеричном формате):

 31 fe 30 00
  

Из них ожидается только первый ( 0x31 = 49 ). Остальные являются неожиданными. [Последнее предложение неверно — см. Раздел ОБНОВЛЕНИЕ / РЕШЕНИЕ]

Я проверил, что этот файл после выполнения первой строки сценария содержит ровно один байт ( 0x30 , который является ASCII-кодом '0' ). Так что это определенно тот .WriteByte() , который добавляет дополнительные символы. [Это утверждение неверно — см. Раздел ОБНОВЛЕНИЕ / РЕШЕНИЕ]

Странно то, что .WriteByte() частично работает так, как ожидалось: очевидно, он перезаписывает первый байт в файле, который находится 0x30 после запуска первой строки скрипта, на 0x31 .

Но почему он добавляет остальные три байта и как мне предотвратить это? Использую ли я .Библиотека NET неправильно установлена из Powershell (новичок Powershell здесь …)? [Этот вопрос недействителен, поскольку .WriteByte() не добавляет остальные три байта — см. Раздел ОБНОВЛЕНИЕ / РЕШЕНИЕ]

ОБНОВЛЕНИЕ / РЕШЕНИЕ

Ответ Матиаса Р. Джессена абсолютно правильный. Тем не менее, я хотел бы кратко объяснить, почему я сам этого не видел (хотя знал о метке порядка байтов раньше):

Я использовал Notepad в сочетании с плагином Hex Editor, чтобы выяснить, что произошло. Очевидно, что у этой комбинации возникают проблемы с обновлением шестнадцатеричного представления открытого файла при изменении файла, поэтому это навело меня на ложный след. Эта проблема возникает у меня уже во второй раз, поэтому в будущем я обязательно буду использовать другие шестнадцатеричные редакторы.

После того, как ответ был написан, я повторно исследовал, на этот раз используя HxD, и сразу увидел, что происходит.

Короче говоря: на самом деле это была не проблема с System.IO.FileStream.WriteByte() , а проблема с инструментами, используемыми для расследования.

Решение простое: если мне нужен один байт в файле, я могу использовать Out-File с другой кодировкой, или я могу использовать .WriteByte() для создания файла в первую очередь.

Ответ №1:

В Windows PowerShell по Out-File умолчанию используется кодировка UTF-16 с начальным порядком (в просторечии известная как Unicode кодировка в Windows).

При выполнении Out-File со значением "0" записывается следующая последовательность байтов в файл на диске:

 ff fe 48 00
___/ ___/
  |     | 
  |    UTF-16LE encoded "0"
UTF-16LE byte order mark
  

При вызове [File]::Open() с [FileMode]::Open помощью он возвращает FileStream объект, указывающий на наименьшее смещение в файле, поэтому WriteByte(49) в конечном итоге перезаписывается первая часть метки порядка байтов:

 49 fe 48 00
 |
Overwritten
  

Если вы всегда хотите перезаписать какие-либо данные в существующем файле, используйте [FileMode]::Truncate :

 $Stream = [System.IO.File]::Open("c:batchvsstest.txt",
                                 [System.IO.FileMode]::Open,
                                 [System.IO.FileAccess]::Truncate,
                                 [System.IO.FileShare]::ReadWrite)
  

Если вы хотите обрезать файл, чтобы избавиться от лишних данных вручную, используйте SetLength :

 $Stream.SetLength(1)
  

Комментарии:

1. Большое вам спасибо, принято и поддержано. Позор мне: я изначально подозревал что-то подобное, но я использовал Notepad с плагином HEX Editor для расследования, который, очевидно, имеет серьезные проблемы с обновлением шестнадцатеричного представления открытого файла при изменении файла. Мотивированный вашим ответом, я снова исследовал, на этот раз используя разумный шестнадцатеричный редактор, и увидел, что происходит именно то, что вы описали. Я » соответствующим образом обновляю свой вопрос и решу проблему, просто используя другую кодировку с Out-File .