2012-08-27 51 views
34

Estoy haciendo mucha manipulación de cadenas en C#, y realmente necesito que las cadenas se almacenen un byte por carácter. Esto se debe a que necesito gigabytes de texto simultáneamente en la memoria y está causando problemas de poca memoria. Sé con certeza que este texto nunca contendrá caracteres que no sean ASCII, por lo que, para mi propósito, el hecho de que System.String y System.Char almacenan todo, ya que dos bytes por carácter son innecesarios y un problema real.Almacenar una cadena como UTF8 en C#

Estoy a punto de comenzar a codificar mis propias clases CharAscii y StringAscii - la cadena uno mantendrá básicamente sus datos como byte [], y expondrá métodos de manipulación de cadenas similares a los que hace System.String. Sin embargo, esto parece mucho trabajo para hacer algo que parece ser un problema muy estándar, así que realmente estoy publicando aquí para verificar que ya no haya una solución más fácil. ¿Hay alguna forma por la que pueda hacer que System.String almacene datos internamente como UTF8 que no he notado, o de alguna otra forma el problema?

+0

¿Es .NET la mejor manera de acceder aquí? Parece que C/C++ sería una mejor opción para la manipulación de cadenas enormes en la memoria. –

+4

Jon Skeet investigó este último año http://msmvps.com/blogs/jon_skeet/archive/2011/04/05/of-memory-and-strings.aspx –

+0

[Somewhere] (http://msdn.microsoft.com /es-es/library/windows/desktop/bb540816%28v=vs.85%29.aspx) hay una cadena utf8 – Gabber

Respuesta

6

Como ha encontrado, el CLR usa UTF-16 para la codificación de caracteres. Su mejor opción puede ser usar las clases de Codificación & BitConverter para manejar el texto. Esta pregunta tiene algunos buenos ejemplos para la conversión entre las dos codificaciones:

Convert String (UTF-16) to UTF-8 in C#

+0

Gracias. Marcó esta como la respuesta ya que el enlace contiene mucha información sobre cómo hacer la conversión. Creo que el enfoque que usted y KeithS sugieren es probablemente el mejor compromiso en mi situación entre un rendimiento máximo y obtener algún tipo de solución que ahorre memoria sin tomar demasiado tiempo para implementarla. – PhantomDrummer

11

Bien, podría crear un contenedor que recupere los datos como bytes UTF-8 y convierta piezas según sea necesario a System.String, y viceversa, para volver a enviar la cadena a la memoria. La clase de Codificación lo ayudará aquí:

var utf8 = Encoding.UTF8; 
byte[] utfBytes = utf8.GetBytes(myString); 

var myReturnedString = utf8.GetString(utfBytes); 
+0

+1, investigué este problema yo mismo al cosechar cantidades masivas de datos para una compañía de bienes raíces y esta solución, aunque un poco mágica y aparentemente janky, es casi lo mejor que pude encontrar en C#. – tmesser

+0

esto termina en el objeto de cadena codificado UTF-16, por cierto. – Tigran

+0

@Tigran, no hay forma de evitarlo si va a usar System.String en cualquier momento. Sin embargo, puede extraer subsecciones de la matriz de bytes codificada y escribirlas de forma controlada, dejando un límite superior a la cantidad de recursos que está absorbiendo. – tmesser

2

No realmente. System.String está diseñado para almacenar cadenas. Su requisito es un subconjunto muy particular de cadenas con beneficios especiales de memoria.

Ahora, "un subconjunto muy particular de cadenas con beneficios particulares de memoria" aparece mucho, pero no siempre el mismo subconjunto muy particular. El código que es solo ASCII no es para ser leído por seres humanos, por lo que tiende a ser códigos cortos, o algo que puede manejarse en una manera de procesamiento de flujo, o fragmentos de texto combinados con bytes que realizan otros trabajos (por ejemplo, bastantes formatos binarios tendrán pequeños bits que se traducen directamente a ASCII).

Como tal, tiene un requisito bastante extraño.

Más aún cuando pasas a la parte de gigabytes. Si estoy lidiando con conciertos, de inmediato pienso en cómo puedo dejar de tener que lidiar con actuaciones y/u obtener ahorros mucho más serios que solo el 50%. Estaría pensando en mapear trozos que actualmente no me interesan en un archivo, o sobre cuerdas, o sobre un montón de otras cosas. Por supuesto, esos van a funcionar en algunos casos y no en todos, así que una vez más, no estamos hablando de algo en lo que .NET debería quedarse en algo como un tamaño único para todos, porque un tamaño no encajará todas.

Más allá de eso, solo el bit utf-8 no es tan difícil. Son todos los otros métodos que se convierten en trabajo. De nuevo, lo que necesitas allí no será lo mismo que otra persona.

+3

No es tan extraño. El OP quiere cadenas que funcionen de la misma manera que 'System.String', pero ocupan la mitad del espacio. Un reemplazo directo, en otras palabras. –

+0

@RobertHarvey Sí, pero ellos p. no querrán una longitud de O (n) porque saben que no la necesitan del conocimiento de sus datos. Alguien con necesidades similares pero no idénticas para una cadena basada en utf-8 necesitará un recuento de O (n) porque no se apega a ASCII solamente. El problema general surge mucho, pero los pequeños detalles varían y eso hace que el reemplazante perfecto de un tipo sea el veneno de otro tipo. –

+0

Robert Harvey lo tiene exactamente. Jon: lo que estoy haciendo, muy aproximadamente, implica extensas referencias cruzadas entre fragmentos de texto. Como tal, sería muy difícil evitar tener todo el texto en la memoria durante el procesamiento. Escribo fragmentos que no me interesan inmediatamente en un archivo, solo para tener que leerlos un milisegundo después, ¡me imagino que sería terrible para el rendimiento! (Además de complicar el código) – PhantomDrummer

1

Como puedo ver, su problema es que el carácter en C# ocupa 2 bytes, en lugar de uno.

Una manera de leer un archivo de texto es abrirlo con:

System.IO.FileStream fs = new System.IO.FileStream(file, System.IO.FileMode.Open); 
    System.IO.BinaryReader br = new System.IO.BinaryReader(fs); 

    byte[] buffer = new byte[1024]; 
    int read = br.Read(buffer, 0, (int)fs.Length); 

    br.Close(); 
    fs.Close(); 

Y de esta manera usted está leyendo los bytes del archivo. Lo probé con *.archivos txt codificados en UTF-8 que es 2 bytes por Char, y ANSI que es 1 byte por Char.

+0

¿Te refieres a UTF-16? UTF-8, como ANSI, será de 1 byte por char para los datos particulares sobre los que estoy preguntando. Pero gracias, de hecho, es exactamente la forma en que leeré los datos. – PhantomDrummer

+0

@PhantomDrummer De hecho, probé UTF-8, la codificación habitual de blocs de notas, y me tomó 2 bytes por char :) me alegro de ayudar – Thanatos

Cuestiones relacionadas