question: strong>
Existe-t-il des appels de l'API Windows (peut-être des NTF) qui permet de diviser un fichier très volumineux en plusieurs autres sans copier des données (en d'autres termes, spécifier les points d'arrêt logiques entre des fichiers joints, avec des noms de fichier et des tailles)? P >
Exemples: em> SetFileValidData, NtsetinformationFile P>
scénario: strong>
J'ai besoin de distribuer / copier de manière programmable 10 Go de fichiers d'un lecteur non local (y compris les lecteurs de réseau, USB et DVD). Ceci est composé de plus de 100 000 fichiers individuels avec une taille médiane d'environ 16 kmbytes, mais ont rejoint ~ 2 Go de morceaux. p>
Cependant, à l'aide d'un simple API de filtream simple (tampon de 64 kb) pour extraire des fichiers des morceaux de lecteurs non locaux vers des fichiers individuels sur un disque dur local semble être limité sur ma machine à environ 4 Mo / s, alors que la copie des morceaux entiers L'utilisation de l'explorateur se produit à plus de 80 Mo / s! p>
Il semble logique de copier des morceaux entiers, mais donnez-vous suffisamment d'informations sur Windows pour diviser logiquement les fichiers (qui devraient être en mesure de se produire très très vite). p>
L'installation de Vista ne fait pas quelque chose comme ça? P>
6 Réponses :
Y a-t-il une raison pour laquelle vous ne pouvez pas invoquer les routines de copie du système d'exploitation pour effectuer la copie? Cela devrait faire la même chose que l'explorateur fait. Cela annule la nécessité de votre traction fractionnée étrange, que je ne pense pas existe. P>
Les routines Direct CopyFile sont légèrement plus rapides que mes propres routines pour copier 100 000 fichiers, mais toujours la performance est horrible (ordre de magnitude plus lente) par rapport à la copie des fichiers fusionnés ensemble. D'où le désir de les copier fusionné, mais divisé après copie.
Bien qu'il y ait des copies ombres volumes, celles-ci constituent une approche tout-ou-rien - vous ne pouvez pas couper une partie d'un fichier. Ils ne sont aussi que temporaires. De même, les liens durs partagent tout le contenu, sans exception. Malheureusement, la découpe seulement des parties d'un fichier n'est pas prise en charge sous Windows, bien que certains systèmes de fichiers expérimentaux de Linux tels que BTRFS le soutiennent. P>
Vous ne pouvez pas en pratique. Les données doivent bouger physiquement, si une nouvelle frontière ne coïncide pas avec une limite de cluster existante. p>
Pour une copie à haute vitesse, lisez le fichier d'entrée de manière asynchrone, rompez-le dans vos segments de 16 kb, postez ceux-ci à une file d'attente (en mémoire) et configurez une threadpool pour vider la file d'attente en écrivant ces segments de 16 Ko. Considérant ces tailles, les écritures peuvent probablement être synchrones. Compte tenu de la vitesse des E / S locaux et des E / S distants, et le fait que vous ayez plusieurs threads d'écrivain, le risque de dépassement de votre file d'attente doit être assez faible. P>
Une pensée à ce sujet: Y a-t-il assez d'espace pour copier le gros morceau sur un lecteur local, puis travailler dessus en l'utilisant comme un fichier mappé en mémoire? Je me souviens d'une discussion quelque part, lorsque ces fichiers sont très plus rapides, car ils utilisent le cache de fichier / page Windows et sont faciles à configurer. P>
de Wikipedia et de Stackoverflow P>
Peut-être que cette technique fonctionnerait pour vous: copiez les gros morceaux (à l'aide de la méthode efficace déjà établie), puis utilisez quelque chose comme le script suivant pour diviser les gros morceaux en morceaux plus petits localement.
from __future__ import division
import os
import sys
from win32file import CreateFile, SetEndOfFile, GetFileSize, SetFilePointer, ReadFile, WriteFile
import win32con
from itertools import tee, izip, imap
def xfrange(start, stop=None, step=None):
"""
Like xrange(), but returns list of floats instead
All numbers are generated on-demand using generators
"""
if stop is None:
stop = float(start)
start = 0.0
if step is None:
step = 1.0
cur = float(start)
while cur < stop:
yield cur
cur += step
# from Python 2.6 docs
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
def get_one_hundred_pieces(size):
"""
Return start and stop extents for a file of given size
that will break the file into 100 pieces of approximately
the same length.
>>> res = list(get_one_hundred_pieces(205))
>>> len(res)
100
>>> res[:3]
[(0, 2), (2, 4), (4, 6)]
>>> res[-3:]
[(199, 201), (201, 203), (203, 205)]
"""
step = size / 100
cap = lambda pos: min(pos, size)
approx_partitions = xfrange(0, size+step, step)
int_partitions = imap(lambda n: int(round(n)), approx_partitions)
partitions = imap(cap, int_partitions)
return pairwise(partitions)
def save_file_bytes(handle, length, filename):
hr, data = ReadFile(handle, length)
assert len(data) == length, "%s != %s" % (len(data), length)
h_dest = CreateFile(
filename,
win32con.GENERIC_WRITE,
0,
None,
win32con.CREATE_NEW,
0,
None,
)
code, wbytes = WriteFile(h_dest, data)
assert code == 0
assert wbytes == len(data), '%s != %s' % (wbytes, len(data))
def handle_command_line():
filename = sys.argv[1]
h = CreateFile(
filename,
win32con.GENERIC_WRITE | win32con.GENERIC_READ,
0,
None,
win32con.OPEN_EXISTING,
0,
None,
)
size = GetFileSize(h)
extents = get_one_hundred_pieces(size)
for start, end in reversed(tuple(extents)):
length = end - start
last = end - 1
SetFilePointer(h, start, win32con.FILE_BEGIN)
target_filename = '%s-%d' % (filename, start)
save_file_bytes(h, length, target_filename)
SetFilePointer(h, start, win32con.FILE_BEGIN)
SetEndOfFile(h)
if __name__ == '__main__':
handle_command_line()
Vous pouvez copier deuxième morceau du fichier dans un nouveau fichier et que tronquer le fichier original. Dans cette approche, vous copiez seulement une moitié de fichier. P>
Je n'utiliserais pas de TfileStream, je suggérerais d'utiliser Thandlestream avec un appel CreateFile qui utilise File_FLAG_SEntene_Scan. Essayez également d'utiliser un tampon de 256 kb, il peut être plus rapide.
Merci Jon pour la suggestion. Oui, j'ai essayé cela et j'ai obtenu une légère meilleure performance (et même essayé file_flag_no_buffering, ainsi que les maux de tête qui impliquent), mais toujours la performance est une commande de grandeur plus lente de copier autant de petits fichiers par rapport à la copie de la fusion.
Comment les fusionnez-vous avant la copie? Pourquoi ne peut-il pas les libérer après la copie?
Voici une torsion - utilisez BitTorrent.