writeline write txt read net from example c# .net text

write - text reader c#



¿Hay una opción "ir a línea" en TextReader/StreamReader? (5)

No puede saltar directamente a una línea en un archivo de texto a menos que cada línea sea de ancho fijo y esté utilizando una codificación de ancho fijo (es decir, no UTF-8, que es una de las más comunes ahora).

La única forma de hacerlo es leer líneas y descartar las que no desea.

Alternativamente, puede poner un índice en la parte superior del archivo (o en un archivo externo) que le indique (por ejemplo) que la línea 1000 comienza en el desplazamiento de bytes [x], la línea 2000 comienza en el desplazamiento de bytes [y] etc. use .Position o .Seek() en FileStream para moverse al punto indexado más cercano y camine hacia adelante.

Asumiendo el enfoque más simple (sin índice), el código en el ejemplo de Jon debería funcionar bien. Si no quiere LINQ, puede activar algo similar en .NET 2.0 + C # 2.0:

// to read multiple lines in a block public static IEnumerable<string> ReadLines( string path, int lineIndex, int count) { if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path"); if (lineIndex < 0) throw new ArgumentOutOfRangeException("lineIndex"); if (count < 0) throw new ArgumentOutOfRangeException("count"); using (StreamReader reader = File.OpenText(path)) { string line; while (count > 0 && (line = reader.ReadLine()) != null) { if (lineIndex > 0) { lineIndex--; // skip continue; } count--; yield return line; } } } // to read a single line public static string ReadLine(string path, int lineIndex) { foreach (string line in ReadLines(path, lineIndex, 1)) { return line; } throw new IndexOutOfRangeException(); }

Si necesita probar los valores de la línea (en lugar de solo el índice de línea), entonces eso es bastante fácil de hacer también; solo modifica el bloque iterador.

Tengo un gran archivo de texto con 25k líneas. Dentro de ese archivo de texto, cada línea comienza con "1 / t (linenumber)"

Ejemplo:

1 1 ITEM_ETC_GOLD_01 골드(소) xxx xxx xxx_TT_DESC 0 0 3 3 5 0 180000 3 0 1 0 0 255 1 1 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 -1 0 -1 0 0 0 0 0 0 0 100 0 0 0 xxx item/etc/drop_ch_money_small.bsr xxx xxx xxx 0 2 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 0 0 0 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1 표현할 골드의 양(param1이상) -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx 0 0 1 2 ITEM_ETC_GOLD_02 골드(중) xxx xxx xxx_TT_DESC 0 0 3 3 5 0 180000 3 0 1 0 0 255 1 1 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 -1 0 -1 0 0 0 0 0 0 0 100 0 0 0 xxx item/etc/drop_ch_money_normal.bsr xxx xxx xxx 0 2 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 0 0 0 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1000 표현할 골드의 양(param1이상) -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx 0 0 1 3 ITEM_ETC_GOLD_03 골드(대) xxx xxx xxx_TT_DESC 0 0 3 3 5 0 180000 3 0 1 0 0 255 1 1 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 -1 0 -1 0 0 0 0 0 0 0 100 0 0 0 xxx item/etc/drop_ch_money_large.bsr xxx xxx xxx 0 2 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 0 0 0 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 10000 표현할 골드의 양(param1이상) -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx 0 0 1 4 ITEM_ETC_HP_POTION_01 HP 회복 약초 xxx SN_ITEM_ETC_HP_POTION_01 SN_ITEM_ETC_HP_POTION_01_TT_DESC 0 0 3 3 1 1 180000 3 0 1 1 1 255 3 1 0 0 1 0 60 0 0 0 1 21 -1 0 -1 0 -1 0 -1 0 -1 0 0 0 0 0 0 0 100 0 0 0 xxx item/etc/drop_ch_bag.bsr item/etc/hp_potion_01.ddj xxx xxx 50 2 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 0 0 0 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 120 HP회복양 0 HP회복양(%) 0 MP회복양 0 MP회복양(%) -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx 0 0 1 5 ITEM_ETC_HP_POTION_02 HP 회복약 (소) xxx SN_ITEM_ETC_HP_POTION_02 SN_ITEM_ETC_HP_POTION_02_TT_DESC 0 0 3 3 1 1 180000 3 0 1 1 1 255 3 1 0 0 1 0 110 0 0 0 2 39 -1 0 -1 0 -1 0 -1 0 -1 0 0 0 0 0 0 0 100 0 0 0 xxx item/etc/drop_ch_bag.bsr item/etc/hp_potion_02.ddj xxx xxx 50 2 0 0 2 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 0 0 0 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 220 HP회복양 0 HP회복양(%) 0 MP회복양 0 MP회복양(%) -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx 0 0 1 6 ITEM_ETC_HP_POTION_03 HP 회복약 (중) xxx SN_ITEM_ETC_HP_POTION_03 SN_ITEM_ETC_HP_POTION_03_TT_DESC 0 0 3 3 1 1 180000 3 0 1 1 1 255 3 1 0 0 1 0 200 0 0 0 4 70 -1 0 -1 0 -1 0 -1 0 -1 0 0 0 0 0 0 0 100 0 0 0 xxx item/etc/drop_ch_bag.bsr item/etc/hp_potion_03.ddj xxx xxx 50 2 0 0 3 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 0 0 0 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 370 HP회복양 0 HP회복양(%) 0 MP회복양 0 MP회복양(%) -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx 0 0 1 7 ITEM_ETC_HP_POTION_04 HP 회복약 (대) xxx SN_ITEM_ETC_HP_POTION_04 SN_ITEM_ETC_HP_POTION_04_TT_DESC 0 0 3 3 1 1 180000 3 0 1 1 1 255 3 1 0 0 1 0 400 0 0 0 7 140 -1 0 -1 0 -1 0 -1 0 -1 0 0 0 0 0 0 0 100 0 0 0 xxx item/etc/drop_ch_bag.bsr item/etc/hp_potion_04.ddj xxx xxx 50 2 0 0 4 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 0 0 0 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 570 HP회복양 0 HP회복양(%) 0 MP회복양 0 MP회복양(%) -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx 0 0

Pregunta: ¿Cómo leo directamente, por ejemplo, la línea 5?


Puede usar mi clase LineReader (ya sea en MiscUtil o en una versión simple aquí ) para implementar IEnumerable<string> y luego use LINQ:

string line5 = new LineReader(file).Skip(4).First();

Esto supone .NET 3.5, hay que admitirlo. De lo contrario, abra un TextReader (por ejemplo, con File.OpenText ) y simplemente llame a ReadLine() cuatro veces para omitir las líneas que no desea, y luego una vez más para leer la quinta línea.

No hay forma de "atajar" esto a menos que sepa exactamente cuántos bytes hay en cada línea.


Si necesita poder saltar a la línea 24,000 usando una función que ReadLine () en el fondo será un poco lenta.

Si el número de línea es alto, es posible que desee hacer una especie de conjetura sobre en qué parte del archivo puede estar la línea y comenzar a leer desde allí. De esa manera, para llegar a la línea 24.567 no tiene que leer 24.566 líneas primero. Puede saltar a algún punto intermedio para averiguar en qué línea está basado en el número después de / t y contar a partir de allí.

Hace un tiempo trabajé con un desarrollador que tenía que construir un DB antes de que los RDBMS fueran comunes. Su solución a su problema fue similar a lo que acabo de escribir, pero en su caso mantuvo un mapa en un archivo separado. El mapa puede asignar cada centésima línea a su ubicación en el documento. Un mapa como este se puede cargar muy rápido y esto puede aumentar los tiempos de lectura. En ese momento su sistema era muy rápido y eficiente para datos de solo lectura, pero no muy bueno para datos de lectura / escritura. (cada vez que cambias las líneas tienes que cambiar todo el mapa, esto no es muy eficiente)


Si se trata de un formato de datos de ancho fijo (es decir, usted sabe que todas las líneas tienen la misma longitud), puede multiplicar la longitud con el número de línea deseado y usar Stream.Seek para encontrar el punto de inicio de la enésima línea .

Si las líneas no son de longitud fija, debe encontrar el número correcto de saltos de línea hasta que esté al comienzo de la línea que desea. Eso sería más fácil de hacer con StreamReader.ReadLine. (Puede hacer un método de extensión para hacer que el archivo sea IEnumerable <cadena> como sugiere Jon Skeet, esto le daría una sintaxis más agradable, pero bajo el capó estará usando ReadLine).

Si el rendimiento es un problema, podría ser (un poco) más eficiente escanear secuencias de bytes <CR> <LF> en el archivo manualmente utilizando el método Stream.Read. No he probado eso; pero el StreamReader obviamente necesita hacer algo de trabajo para construir una cadena fuera de la secuencia de bytes: si no te importan las primeras líneas, este trabajo se puede guardar, así que teóricamente deberías poder hacer un método de escaneo que funcione mejor . Sin embargo, esto sería mucho más trabajo para ti.


Si va a buscar muchas líneas diferentes del archivo (pero no todas), entonces puede obtener algún beneficio de crear un índice sobre la marcha. Utilice cualquiera de las sugerencias que ya están aquí, pero a medida que avanza construya una matriz de desvíos de bytes para cualquier línea que ya haya localizado, de modo que pueda evitar volver a escanear el archivo desde el principio cada vez.

APÉNDICE:
Hay otra manera de hacerlo rápido si solo necesitas la línea ocasional "aleatoria", pero a costa de una búsqueda más complicada (si la respuesta de Jon es lo suficientemente rápida, definitivamente me quedaré con eso por simplicidad).

Podría hacer una "búsqueda binaria", al comenzar a buscar a la mitad del archivo para la secuencia "1", la primera aparición que encuentre le dará una idea del número de línea que ha encontrado; luego, en función de dónde está la línea que está buscando en relación con el número encontrado, sigue dividiéndose recursivamente.

Para un rendimiento adicional, también puede suponer que las líneas tienen aproximadamente la misma longitud y el algoritmo ''adivina'' la posición aproximada de la línea que está buscando en relación con el número total de líneas en el archivo y luego realiza esta búsqueda desde allá en adelante Si no quiere hacer suposiciones sobre la longitud del archivo, puede incluso hacer que se auto-prime simplemente dividiendo por la mitad primero, y usando el número de línea que encuentra primero como una aproximación de cuántas líneas hay en el archivo como entero.

Definitivamente no es trivial de implementar, pero si tienes mucho acceso aleatorio en archivos con una gran cantidad de líneas, puede rendir en ganancias de rendimiento.