




Вам нужно использовать кодировку (System.Text.Encoding), чтобы сообщить .NET, что вы ожидаете в качестве вывода. Например, в UTF-16 (= System.Text.Encoding.Unicode):
var result = System.Text.Encoding.Unicode.GetBytes(text);
Джоэл: Поэтому я написал «например». ;-) Но ваш комментарий, конечно, верен.
:) Пытаясь показать, где находятся кодировки, отличные от UTF16, я, наверное, мог бы сформулировать это лучше.
не могли бы вы увидеть мой вопрос, связанный с этим?
Нравится:
string test = "text";
byte[] arr = Encoding.UTF8.GetBytes(test);
Какую кодировку вы используете? У Конрада это в значительной степени не так, но есть и другие, и вы можете получить глупые результаты, используя неправильный:
byte[] bytes = System.Text.Encoding.XXX.GetBytes(text)
Где XXX может быть:
ASCII
BigEndianUnicode
Default
Unicode
UTF32
UTF7
UTF8
Сначала определитесь, какую кодировку вы хотите: сначала вам нужно знать немного о Unicode.
Затем определите, какому System.Text.Encoding соответствует. Мой Справочная карта Core .NET описывает большинство распространенных и то, как получить экземпляр (например, с помощью статического свойства Encoding или путем вызова Encoding.GetEncoding.
Наконец, определитесь, хотите ли вы использовать все байты сразу (это самый простой способ работы - вызовите Encoding.GetBytes (строка) один раз, и все готово) или вам нужно разбить его на куски - в этом случае вы захотите использовать Encoding.GetEncoder а затем кодировать по частям. Кодировщик заботится о сохранении состояния между вызовами, например, в случае, если вам нужно прервать половину пути через символ.
@JonSkeet: Вам действительно не нужна кодировка, если вы (или кто-то другой) на самом деле не собираетесь интерпретировать байтов, не так ли? Для таких задач, как сжатие, шифрование, обфускация и т. д., Кодирование кажется несущественным ... нет причин испытывать проблемы, если они вам не нужны ..
@Mehrdad: Ты, абсолютно, знаешь. Кодировка определяет, что делает преобразование из строки в массив байтов. Сжатие и шифрование - это разные вещи. В противном случае это все равно, что сказать, что формат изображения не имеет значения, когда вы хотите сохранить изображение в виде файла - много разных форматов изображений могут быть в порядке, но по определению должен быть задействован один.
@JonSkeet: Разве ты не можешь просто сказать byte[] bytes = new byte[str.Length * sizeof(char)]; Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length)? Кого волнует, какая кодировка (или если в строке вообще есть действительные символы), если вы знаете, что можете вернуть ее в той же форме, сделав обратное?
@Mehrdad: Значит, это UTF-16. Это все еще кодировка - просто она естественная, используемая для внутреннего использования для char. (И вас может очень заботить тот факт, что это вдвое больше, чем должно быть, если ваша строка полностью состоит из ASCII.)
@JonSkeet: Верно, но моя точка зрения в том, что простой факт, что пользователь хочет «получить байты», не означает, что ему даже нужно знать, какое «кодирование» средства вообще ... это имеет значение, только если он устный перевод их , а не просто работать с ними как с черным ящиком. (Что касается проблемы с пространством: да, это, очевидно, проблема с мог, но довольно часто, когда вам «нужны просто байты», это не имеет значения, как я предполагаю, дело было здесь. Очевидно, что выгодный знать о кодировках, но вы разве необходимость не знает о них здесь, а?)
@Mehrdad: Нет, пользователю делает необходимо знать кодировку. Тот факт, что UTF-16 в некотором смысле является естественной кодировкой для .NET, не означает, что это кодировка, которую он хочет использовать. Смысл записи данных в том, чтобы их можно было прочитать снова - и для этого потребуется использовать ту же кодировку. Тот факт, что OP ссылается на «эквивалентный массив байтов», предполагает, что они не знают, что кодировки вообще существуют, и что жизненно важно понимать кодировки, если вы собираетесь преобразовывать между текстовым и двоичным представлениями.
Я видел, как люди бесчисленное множество не могут правильно сохранять информацию, потому что они не понимают кодировки. По моему опыту, обучение их этой теме - гораздо лучший подход, чем использование Buffer.BlockCopy и предполагая, это то, чего они хотят.
@JonSkeet: Тогда что делать, если какой-то символ в строке недействителен в кодировке, для которой вы хотите «получить байты» (возможно, потому что кто-то еще дал вам строку, и вы не несете ответственности за ее содержимое ... может быть, у него есть символы частного использования, или, может быть, они даже не сказать вам кодировку)? Использование какой-либо конкретной кодировки не имеет смысла, потому что для ваших символов может не быть никакого преобразования. Напротив, если вы просто используете метод, который я упомянул, тогда не имеет значения, действительны ли символы, потому что они в любом случае будут работать правильно.
@Mehrdad: строка не кодирует имеют (или всегда UTF-16). Если он читается из UTF-8, он все равно попадает в UTF-16 внутри. Дело не в том, что ваш метод не использует кодировку - дело в том, что это скрытый, что IMO плохо. Очевидно, вам нужно использовать кодировку соответствующий, но просто попытаться отмахнуться от проблемы, как если бы ее не было, - действительно, очень плохая идея, ИМО. Сохранение незнания кодировок - это нет путь вперед. Если вы хотите использовать UTF-16, сделайте это явно (Encoding.Unicode).
@JonSkeet: Я не понимаю вашего комментария «Строка не имеет кодировки (или всегда UTF-16)» ... эти двое идут друг против друга. Должен ли System.String всегда содержать UTF-16? Если на то пошло, должен это подчиняется какой-то другой конкретной кодировке?
@Mehrdad: Это всегда последовательность char, которая сама по себе является единицей кода UTF-16. (Обратите внимание, что это не кодовая точка Unicode.) Но бессмысленно говорить, например, о «строке UTF-8». У вас может быть «представление строки в кодировке UTF-8» (которое будет массивом байтов), но это другое дело.
@JonSkeet: Я не понимаю. Если вы утверждаете, что string всегда должен содержать действительные данные UTF-16, то это неверно ("\uFFFF\uFFFF"). И если вы утверждаете, что не обязательно содержит действительные данные UTF-16 и что он может представлять данные в более, чем одна возможная кодировка, тогда я прошу вопрос: какой смысл использовать Encoding.XXX.GetBytes() в строке, когда вы не Не знаете, какую кодировку использовать? (Это не похоже на то, что люди дают вам кодировку для каждого отдельного объекта string, который они передают вам ...)
@Mehrdad: Это зависит от того, что вы имеете в виду под словом «действительный». По определению, он всегда содержит кодовые единицы UTF-16. Конечно, им не нужно сопоставляться с определенными символами Unicode ... но они по-прежнему UTF-16. Поэтому, если вы хотите представить какое-то значение в частном диапазоне, вы делаете это в UTF-16, а затем конвертируете в кодировку UTF-8 (или любую другую) те же символы частного диапазона позже. Если вы не знаете, какую кодировку использовать, вы вообще преобразуете не следует в байты. Это все равно, что просить сохранить изображение без указания формата изображения - просто скажите «нет».
@JonSkeet: Извините, это из будущего, не знаю, как я пропустил комментарий ... но имеет смысл зашифровать / сжать строку для транспортировки / хранения, не зная (или не заботясь), какую кодировку использовать. Кодирование вообще не нужно задействовать во многих подобных сценариях.
@Mehrdad: Можно сжимать, а затем распаковывать какое-то двоичное представление строки, не зная, в какой кодировке оно используется. нет отлично подходит для обработки сжатых двоичных данных, как если бы это был текст. Каждый раз, когда вы хотите преобразовать строку в двоичную или наоборот, вы должен знаете, какую кодировку использовать, и будете согласованы в обоих направлениях.
@JonSkeet: Да, это именно то, что я сказал, верно? Пока вы не пытаетесь интерпретировать байтов, вам не нужно беспокоиться о кодировке. :)
@Mehrdad: Но кто-то будет интерпретировать байты позже. Вы правы в том, что часть сжатия / шифрования не нуждается в заботе, но то, что позже превратит ее обратно в строку, обязательно ... и если никто Когда-либо не будет интерпретировать данные, там не так много точка в том, чтобы быть там. Так что да, вам все равно нужно выбрать кодировку и убедиться, что она используется последовательно. Какую кодировку вы решите использовать, является произвольной в некотором роде, если она может кодировать весь ваш текст, хотя это повлияет на пространство и т. д. Произвольная - это не то же самое, что и нерелевантная.
@JonSkeet: Итак, вы говорите, что я должен выбираю кодировку, если, например, все, который я делаю, конвертирую string в byte[], сжимаю его и записываю в файл, чтобы завтра я мог прочитать его в byte[] и распаковать его в string на той же машине? Если так, я нахожу это заявление немного шокирующим - почему кодировка имеет значение? Да, завтра я «интерпретирую» строку, но какое значение имеет кодировка? Единственное, что имеет значение, это то, что я возвращаю то, с чего начал ... и все.
@Mehrdad: Да, конечно. Так же, как вы должен выбираете формат изображения, если хотите сохранить изображение на диск. Используйте эту аналогию, насколько можете. Строки не состоят из байтов (концептуально), поэтому для преобразования байтов к вы должны пройти какое-то преобразование ... и это именно кодировка.
@JonSkeet: Э ... да, это должен проходит через преобразование немного, это правда по определению. Но ты не обязательно для забота, какое конкретное преобразование является, пока черный ящик может декодировать байты за вас. Верно? Я чувствую, что это должно быть очевидно ... зачем вам все равно, что такое внутри в коробке (конкретная кодировка)? Итак, вам не нужно знать что-нибудь о как, он работает (или какое слово "кодировка" даже средства!) ... все вам нужен, это byte[] GetBytes(string) и string GetString(byte[]), и все! И это то, что делает BitConverter, никаких проблем с кодированием.
Другими словами, для человека должно быть вполне возможно и законно знать ничего такого о кодировках (и никогда не необходимость to) и запрашивать «представление byte[]» строки, если он никогда не собирается интерпретировать байтов. Это все, что я говорю - ответ, в котором для преобразования используется BitConverter (или что-то подобное), легко справился бы с этой задачей, и он бы сделал это без упоминания слова «кодировка» ни разу - так что на самом деле кодировка не является Это то, о чем OP должен должен беспокоиться.
@Mehrdad: Кодировка является - черный ящик. Есть много черных ящиков на выбор (разные кодировки). Вам не нужно ничего знать о внутреннем устройстве, но вам нужно выбрать одно и то же преобразование в обоих направлениях. Ответ с использованием BitConverter все еще выбирает кодировку - он просто предпочитает не называть это так. Вы бы предпочли, чтобы я сказал: «Вам нужно выбрать преобразование строки в байты, обычно через System.Text.Encoding»? Это точно то же самое, только более коряво сказано в ИМО. Опять же, подумайте о форматах изображений: вам нужно выбрать формат для перехода от пикселей к байтам.
Важным моментом является то, что пользователь не может запрашивать представление вbyte[], потому что доступно множество различных опций.
@JonSkeet: «Вы бы предпочли, если бы я сказал:« Вам нужно выбрать преобразование строки в байты, обычно через System.Text.Encoding »» - Да! Точно: если бы вы сказали это, то пользователю нужно было бы знать ничего такого о Unicode, чтобы достичь своей цели! Это - ключевое различие между Text.Encoding и BitConverter - один из них предназначен для случаев, когда делать заботится о кодировке, а другой - для случаев, когда кодирование на 100% не имеет отношения к вашей цели. Вот почему я здесь прокомментировал: вы сказали OP потребности знать о Unicode, когда на самом деле это не имеет значения (просто используйте BitConverter).
@Mehrdad: Использование BitConverter по-прежнему означает выбор, просто не осознавая, что есть варианты являются. (Кроме того, я не могу найти, какой метод BitConverter вы имеете в виду, если честно.) Опять же, подумайте о версии изображения: если бы кто-то спросил вас, как сохранить изображение на диск, вы бы не задались естественным вопросом о том, какой формат? Я не понимаю, почему для кого-то должно быть спорным знание довольно простой разницы между байтами и символами и возможность выбирать разные кодировки. Не похоже, что они должны воплощать в жизнь их.
@JonSkeet: Ой, извиняюсь за упоминание BitConverter, я имел в виду System.Buffer.BlockCopy, который может копировать любой примитивный массив (например, char[]) в byte[] и наоборот ... Я думал не о том классе, извините за то, что сбил вас с толку.
@JonSkeet: Что касается задачи с изображением: это то же самое. Если BlockCopy может выполнять кодирование / декодирование в вашем классе Picture, тогда вам нужно знать ничего такого о различных форматах изображений (или даже их существование), чтобы достичь того, что вам нужно, если вы никогда не собираетесь использовать устный перевод байтов самостоятельно. . Нет необходимости говорить пользователю, что он хочет узнать о BMP. Это гораздо меньшее препятствие, которое нужно преодолеть (вообще-то, нет), чем изучение Unicode!
У вас есть пример класса изображений .NET, который мог обрабатывает Buffer.BlockCopy? Вам не нужно знать много о Unicode, хотя, очевидно, чем больше, тем лучше. Но вам делать нужно сделать выбор. Если вы хотите написать класс StringConverter, который скрывает этот выбор, а всегда использует Encoding.UTF8 (или что-то еще), тогда продолжайте - но вы все равно делаете выбор, и я не думаю, что кому-то действительно выгодно скрывать его. Рано или поздно вы обязательно столкнетесь с ситуацией, когда вам нужно понять самые основы кодирования, так почему бы не научиться раньше, чем позже?
@Mehrdad, позволяя черному ящику произвольно выбирать кодировку и особенно полагаясь на лежащее в основе .net представление строки в UTF-16, вы вводите будущие потенциальные ошибки. Что, если следующее обновление системы .net изменит способ представления строк в памяти? Например, вместо Little-Endian это может быть Big-Endian. Предположим, мы конвертируем строку в массив байтов, а затем сжимаем ее. После нескольких месяцев и обновления .net мы пытаемся распаковать и преобразовать обратно в строку. Но на этот раз будет фигня! Все потому, что кодировка явно не указана.
@ThanasisIoannidis: Прошло 5 лет, но, оглядываясь назад, кажется, что я довольно ясно дал понять, что нужно ли указывать кодировку или нет, зависит от того, что именно вы пытаетесь сделать. И обратите внимание, что это нет, «позволяющий черному ящику выбирать кодировку». BlockCopy нигде не решает какую-либо кодировку, и в этом суть. например Если вам нужна передача без потерь в идентичной системе, вы должны использовать необработанные байты независимо от того, действительны ли они в соответствии с какой-либо конкретной кодировкой. OTOH, если вам нужна совместимость, вы кодируете / декодируете.
@Mehrdad при условии, что в первую очередь есть необработанные байты. Бывает, что .net реализует строки с базовым массивом символов, но это детали реализации. Даже между идентичными системами никто не гарантирует, что будет базовый массив для получения необработанных байтов. Он может легко превратиться в связанный список или любую другую структуру данных (маловероятно, но все же вы поняли). Тем не менее, вам нужно будет указать способ преобразования этой строки (с этой странной базовой реализацией) в последовательность байтов, и этот способ преобразования из строки в байт называется кодировкой.
@ThanasisIoannidis: Прежде всего, C# позволяет закрепить строку и напрямую обращаться к основным символам, так что вы сразу ошибаетесь. Во-вторых, даже если бы это было не так, связанный список (или что-то еще) ничего бы не изменил. Какой бы ни была основная реализация, у вас есть Buffer.BlockCopy() и string.ToCharArray, которые дают вам необработанные байты, которые можно использовать для идеальной реконструкции. Посылают ли они кого-нибудь, чтобы подняться на Эверест и передать персонажей по радио на Луну и обратно, зависит от структуры, а не от вашего дела, и это совершенно не имеет значения.
@ThanasisIoannidis: Представьте, что вы пишете коммуникационную библиотеку для вашей программы, которая работает на двух машинах, возможно, с API void Send(string), string Receive(). Вы действительно должен иметь возможность передавать string сам по себе точно так же, как вы передаете char[] или byte[]. На самом деле ваша библиотека не касается, является ли этот string UTF-16LE, UTF-16BE или иначе. Это могут быть совершенно случайные единицы кода для всего, что вам нужно. Ваша библиотека может и должна выполнять свою работу по передаче без потерь в любом случае. И предполагать, что внутреннее кодирование не просто необходимо; это теряет информацию.
@Mehrdad, что касается массива символов, это не массив байтов, пока к нему не применяется тип кодирования немного. BlockCopy выполняет эту кодировку в вашем случае, даже если эта кодировка - это просто копирование памяти каждого байта массива char. Это не обязательно должен быть один из System.Text.Encodings (чтобы не потерять информацию). Какой бы способ вы ни использовали для получения массива байтов, это кодировка. Контракт о том, как получить byte [] из строки. Если упомянутая вами библиотека предназначена для преобразования туда и обратно в одной и той же или идентичных системах, да, вам не нужно указывать кодировку. Библиотека сделает это за вас.
Но даже с той же библиотекой, если она полагается на базовую реализацию, могут появиться ошибки. Вы не можете гарантировать, что система будет идентична при декодировании. Что, если .net изменится с Little-Endian на Big-Endian на принимающей части передачи? ToCharArray будет кодировать в Little-Endian, а FromCharArray на принимающей части будет использовать Big-Endian, что приведет к повреждению данных. Очевидно, ваш путь - это способ конвертировать string в byte[] в .net. Но явное указание кодировки - это еще один способ преобразования string в byte[], который кажется более надежным.
@ThanasisIoannidis: Вопрос в том, что кто предоставляет контракт какие и должен ли вызываемый абонент заботиться об этом или нет. Но в этот момент вы просто повторяете себя. Мне нечего добавить. Не стесняйтесь двигаться дальше.
не могли бы вы увидеть мой вопрос, связанный с этим?
@Faisal: пожалуйста, не используйте комментарии к старым вопросам (в данном случае более десяти лет назад), чтобы привлечь внимание к новому вопросу, если только конкретно нового вопроса не вышло из обсуждения в существующих комментариях.
В System.Text.Encoding гораздо больше кодировок, чем просто Unicode: убедитесь, что вы понимаете, какая из них вам нужна.