#.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
.