2012-08-06 9 views
7

Sto accostando un file per mezzo di un FileStream (si tratta di un file molto grande e ho solo bisogno di modificare l'intestazione senza dover riscrivere il tutto.Come posso rilevare se un file ha feed di riga Unix ( n) o feed di riga di Windows ( r n)?

Il file può avere sia Unix o linea di Windows si nutre, e è importante per me sapere in che modo posso scrivere i caratteri della riga corretta nel file quando lo aggiorno.

Potrei scrivere una semplice funzione per usare un FileStream per leggere il file in blocchi e verificare la presenza di caratteri di avanzamento riga.

Ma questo problema deve essere stato risolto prima, se non in C# poi nel API Win32?

Qual è il modo più efficiente per rilevare lo stile di avanzamento riga del file?

+0

Non sono sicuro, quindi il commento, ma sarebbe possibile utilizzare un'espressione regolare come: '\ r \ n $'? Questo controllerebbe che l'avanzamento della riga termini con un \ r \ n'. In caso contrario, deve essere una linea Unix. – npinti

+0

Non proprio possibile, poiché l'utilizzo di uno qualsiasi dei metodi "ReadLine" sugli oggetti di accesso al file framework .Net elimina i caratteri di nuova riga. Sono buoni se non ti interessa quale stile newline sta usando un file. Se leggo il file come uno stream, potrei fare qualcosa come suggerisci tu (che sostanzialmente equivale al metodo a cui potrei ricorrere ..) – freshr

+0

Puoi garantire che tutte le terminazioni di riga siano coerenti all'interno di un file? Tecnicamente sarebbe possibile avere terminazioni di linea misti in modo diverso all'interno dello stesso file. –

risposta

2

Grazie a tutti per i vostri suggerimenti. Sono stato sorpreso di non trovare qualcosa facilmente riusabile, quindi ho creato una semplice funzione che includo qui.Si noti che trova solo il primo carattere di nuova riga (\ n o \ r \ n) e lo restituisce come corrispondenza. Abbastanza per i miei bisogni, ma forse non robusto.

public bool TryDetectNewLine(string path, out string newLine) 
    { 
     using (var fileStream = File.OpenRead(path)) 
     { 
      char prevChar = '\0'; 

      // Read the first 4000 characters to try and find a newline 
      for (int i = 0; i < 4000; i++) 
      { 
       int b; 
       if ((b = fileStream.ReadByte()) == -1) break; 

       char curChar = (char)b; 

       if (curChar == '\n') 
       { 
        newLine = prevChar == '\r' ? "\r\n" : "\n"; 
        return true; 
       } 

       prevChar = curChar; 
      } 

      // Returning false means could not determine linefeed convention 
      newLine = Environment.NewLine; 
      return false; 
     } 
    } 
2

Purtroppo non penso che ci sia un modo per essere sicuri al 100% se si tratta di un file Unix o DOS poiché la maggior parte degli editor non corregge un file con terminazioni "errate" quando vengono aperti/salvati.

avrei letto il file come un flusso e la ricerca di occorrenze di "\ r \ n" e solo '\ n'

Utilizzando una semplice analisi statistica (vale a dire che si ha il più alto numero di passaggi) sulla il risultato della ricerca probabilmente ti darà la risposta corretta. Se il file è enorme, sarà sufficiente leggere il primo X% del file.

Una soluzione più semplice è ovviamente cercare solo "\ r \ n" e se trovato, si supponga che sia un file DOS. Questo dovrebbe funzionare al 100% se il file è generato da una macchina.

Come per qualsiasi codice esistente in .NET Framework/WinAPI, non ho ancora visto nessuno che esegua questa operazione.

3

Come detto, non c'è davvero modo di ridurre il contenuto di un file di testo senza aprirlo e scorrere i byte. Potresti ottenere un guadagno se utilizzi http per scaricare il file, potresti ottenere un tipo mime che identifica il tipo di file, ma molto spesso è solo "ottetto-stream".

Mentre è possibile eseguire la forza bruta e leggere finché non si trova un avanzamento riga ("\ n"), quindi eseguire il backup di un carattere e vedere se è presente un ritorno a capo ("\ r"), prenderei uno più statico approccio poiché è necessario leggere i dati in qualsiasi modo.

1) Selezionare una dimensione di esempio di byte da leggere che dovrebbe ottenere almeno 2 o 3 record dal file.

2) Memorizza ogni byte di incontro (i'massumign single byte char set qui) come istogramma. Puoi farlo memorizzando il tuo conteggio in un arry indicizzato dal valore del byte o potresti usare un dizionario.

3) Dai un'occhiata al conteggio dei valori di ritorno a capo e avanzamento riga. Se si dispone di un conteggio degli avanzamenti riga e nessun ritorno a capo, allora si tratta di un file unix. Se il ritorno di carraige e il conteggio dei feed di riga, allora è un file di Windows.

Ciò che questo approccio consentirebbe anche di fare è un controllo di qualità sul file in entrata. Hai dei charcaters nell'istogramma che non sono aplha numerici? Poi qualcuno ti ha passato un file binario. Aspettando tutto il maiuscolo? Quindi cerca i conteggi al di fuori dei caratteri maiuscoli. Ci sono un certo numero di controlli che puoi fare per evitare di elaborare un file non di testo.

+1

Sia la tua soluzione che quella di @Per suppongono che tutte le terminazioni di riga siano coerenti per file .In natura, potrebbe tecnicamente essere molto ben possibile avere marcatori di fine linea mista. –

+2

Vero, ma l'esercizio qui è a detrmine se un il file è unix o windows.Vedo che i file in entrata sono in un formato o l'altro a causa di ciò che è indicato nella domanda.Se ci si aspetterebbe un misto di record terminati LF e CR/LF, allora probabilmente non importa quale sia l'intestazione la riga è stata terminata con. – user957902

Problemi correlati