2009-07-27 5 views
9

BACKGROUNDfile Accesso al di là MAX_PATH in C# /. NET

ho bisogno di scrivere uno strumento utilizzando .NET versione 2.0 a più alto (usando qualcosa dallo scaffale non è un'opzione per questo client per politica, commerciale, e ragioni di confidenzialità/fiducia) per migrare i file da un server all'altro attraverso la rete. I server sono file server per i team locali e alcune cartelle del team devono essere migrate su altri server per facilitare una riorganizzazione. L'idea di base è che leggiamo ogni file e lo riversiamo sulla rete fuori dalle ore e dopo alcuni giorni i dati verranno migrati. Le autorizzazioni per i file devono essere preservate. Poiché ci vorranno alcuni giorni (stiamo parlando di diversi gigabyte di dati, per alcuni team), è necessario eseguire iterazioni sui file ogni notte e confrontare le date di modifica e aggiornare quelle che sono state modificate. La teoria è che alla fine il nuovo server avrà una copia aggiornata dei file e gli utenti potranno passare al nuovo server. E ', naturalmente, non del tutto questo semplice, ma abbiamo un progetto che pensiamo dovrebbe funzionare :)

IL PROBLEMA

Quindi, in teoria abbiamo Basta aprire il file, lo streaming attraverso la rete, e scrivere dall'altra parte, giusto? :)

Purtroppo, sui server stessi, le condivisioni di file sono stati creati in percorsi delle cartelle, come:

D: Le Azioni \ Data \ squadra \ DIVISIONE \ DIPARTIMENTO \ NOME DEL TEAM - potrebbe essere abbastanza lungo \

Per ogni utente, questo percorso è mappato su un'unità, ad esempio sarebbe condiviso come \\ SERVER \ TEAMNAME e mappato sull'unità T :.

Ciò ha causato la situazione in cui i file come visibili dall'unità T: sono all'interno della limitazione MAX_PATH, tuttavia se visualizzati localmente sul server stesso, vanno ben oltre. Non possiamo accedere ai file utilizzando le condivisioni di rete poiché questo strumento deve essere generico, da eseguire su centinaia di questi server e non esiste un modo standard per dire quali condivisioni di file sono quelle che dovremmo spostare e quelle che non lo sono - c'è nessun standard di convenzione di denominazione nemmeno. Inoltre, occasionalmente ci sono sotto-azioni di altre azioni e quindi superiamo il limite di MAX_PATH due volte!

Sono a conoscenza della soluzione alternativa per specificare i percorsi utilizzando il prefisso "\\? \", Che considera il percorso come un percorso UNC e consente un massimo teorico di 32 caratteri.

Questa soluzione alternativa è implementata a livello di API Win32, lo spazio dei nomi System.IO è (principalmente) fondamentalmente solo un involucro sottile attorno alle funzioni API Win32 native, tuttavia Microsoft ha "abilmente" implementato la convalida aggiuntiva (errata) prima di consegnare la chiamata fuori dall'API. In questo caso, .NET Framework rifiuta il percorso perché afferma che "?" è un carattere di percorso non valido.

Quindi la mia domanda è ... c'è un modo in cui non ho pensato che mi permetterà di aggirare questo senza dover riscrivere completamente l'intero spazio dei nomi System.IO, facendo un carico di P/Invoke chiama, solo per rimuovere questa fastidiosa convalida?

risposta

5

Il team BCL ha fatto una serie in 3 parti sul perché esattamente queste scelte sono state fatte e su quali sono le attività in giro.Se non avete letto che ancora vi suggerisco di fare come è una grande fonte di informazioni sul tema

+1

Sì, l'ho visto. La loro soluzione raccomandata è ciò che sto cercando di evitare di essere onesto. Poiché abbiamo a che fare con metadati di file e directory, permessi e contenuti di file, questo fa un sacco di chiamate API, e speravo davvero che qualcuno avesse una soluzione praticabile che significherebbe che non avrei dovuto passare il mese successivo a pinvoke.net;) –

+0

Le mie e altre risposte [qui] (http://stackoverflow.com/a/29605805/589059) suggeriscono alcune librerie wrapper che è possibile utilizzare per gestire percorsi lunghi. – rkagerer

1

Dovrebbe essere abbastanza facile da aggirare questa limitazione con un po 'di piattaforma invocano, supponendo che il software disponga delle autorizzazioni necessarie:

[DllImport("kernel32.dll", SetLastError = true)] 
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, 
    uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, 
    uint dwFlagsAndAttributes, IntPtr hTemplateFile); 

// Must close/dispose handle separately from FileStream since it's not owned by 
// that object when passed to constructor. 
using (SafeFileHandle h = CreateFile(longUncPath, GENERIC_WRITE, 0, IntPtr.Zero, 
     OPEN_EXISTING, 0, IntPtr.Zero)) 
{ 
    using (var fs = new FileStream(h, FileAccess.Read)) 
    { 
     // operations with FileStream object 
    } 
} 
+1

Quando la mia classe di definizioni P/Invoke ha ottenuto circa 3000 righe di varie importazioni, strutture e costanti e ancora non avevo tutte le funzionalità di cui avevo bisogno pensavo di venire qui prima e vedere se mi mancava qualcosa di ovvio .. . sembra non :( –

+0

Gotcha. E non c'è nessuna soluzione di terze parti esistente? Sono sorpreso! –

+0

@ Ben: Controlla la mia risposta. –

4

mi sono imbattuto in una soluzione di terze parti che possono aiutare: AlphaFS.

0

Ho avuto successo cancellando le strutture di directory usando sotto piccolo script. pushd utilizza il formato UNC che fornisce 32K invece di 260 limitazione

set "folder=\\SERVER\SHARE\DIVISION\DEPARTMENT\NAME OF TEAM - COULD BE FAIRLY LONG\" 
pushd "%folder%" 
for /d %%i in ("*") do rmdir "%%i" /s /q 
popd