Разделить большой файл без копии?

Хотя это было намного больше, чем "несколько дней", я полагал, что должен, вероятно, включить свое текущее решение здесь.

Nils Pipenbrinck входил в то же направление как мой существующий метод. Так как одним из основных результатов нахождения клонов являются огромные сбережения от серьезной архивации, я полагал, что мог просто попытаться сжать любые два ROMs вместе и видеть, сколько свободного места было оставлено. Я использую алгоритм LZMA в 7zip для этого.

первый шаг должен сжать каждый ROM индивидуально и отметить сжатый размер, затем попытаться архивировать любые два ROMs вместе и видеть, насколько получающийся размер отличается от сжатых размеров их человека. Если объединенный размер совпадает с суммой отдельных размеров, они на 0% подобны, и если размер совпадает с одним из них (самый большой), они идентичны.

Теперь, это - огромное количество требуемых попыток сжатия, таким образом, у меня есть несколько оптимизации до сих пор (и хотел бы выяснить больше):

  1. Располагают по приоритетам сравнения на основе того, насколько подобный сжатые размеры. Если ROM A имеет сжатый размер 10 МБ, и ROM B имеет сжатый размер 2 МБ, для них невозможно быть больше, чем подобных 20%, настолько выдерживающих сравнение их для получения реального результата можно оставить до позже. Выполнение того же алгоритма сжатия для высоко подобных файлов имеет тенденцию приводить к результатам подобного размера, таким образом, это находит много клонов очень быстро.

  2. Объединенный с вышеупомянутым, сохраните и верхние и более низкие "границы" на возможном подобии между любой парой ROMs. Это позволяет дальнейшее установление приоритетов. Если ROMs A и B на 95% подобны, и ROMs B, и C только на 2% подобны, то Вы уже знаете, что A и C между 0% и 7%. Это слишком низко, чтобы быть клоном, таким образом, это сравнение может быть безопасно отложено или даже проигнорировано полностью, если я действительно не хочу знать точные общие черты всего.

7
задан tikinoa 6 October 2009 в 23:55
поделиться

6 ответов

Вы не можете на практике. Данные должны физически перемещаться, если какая-либо новая граница не будет совпадать с существующей границей кластера.

Для высокоскоростного копирования считайте входной файл асинхронно, разбейте его на сегменты по 16 КБ, поместите их в очередь (в памяти) и настройте пул потоков для очистки очереди путем записи этих сегментов по 16 КБ. Учитывая эти размеры, записи, вероятно, могут быть синхронными.

3
ответ дан 7 December 2019 в 12:22
поделиться

Хотя есть теневые копии тома, это подход "все или ничего" - вы не можете просто вырезать часть файла. Они тоже временные. Точно так же жесткие ссылки передают весь контент без исключения. К сожалению, вырезание только частей файла не поддерживается в Windows, хотя некоторые экспериментальные файловые системы Linux, такие как btrfs, поддерживают это.

3
ответ дан 7 December 2019 в 12:22
поделиться

Мысль по этому поводу: достаточно ли места для копирования большого фрагмента на локальный диск и последующей работы с ним, используя его как файл с отображением памяти? Я помню, как где-то обсуждалось, что эти файлы работают намного быстрее, поскольку они используют кеш файлов / страниц Windows и их легко настроить.

Из Википедии и из StackOverflow

0
ответ дан 7 December 2019 в 12:22
поделиться

Есть ли причина, по которой вы не можете вызвать подпрограммы копирования ОС для выполнения копирования? Это должно делать то же самое, что и Explorer. Это сводит на нет необходимость в вашей странной штуке с расщеплением, которая, я думаю, не существует.

-1
ответ дан 7 December 2019 в 12:22
поделиться

Perhaps this technique would work for you: Copy the large chunks (using the already established efficient method), then use something like the following script to split the large chunks into smaller chunks locally.

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()

This is a Python 2.6 script utilizing pywin32 to utilize the Windows APIs. The same technique could be implemented in Delphi or C++ easily enough.

The main routine is in handle_command_line. It takes a filename, and splits that filename into chunks based on the get_one_hundred_pieces function. Your application would substitute a more appropriate function to determine the appropriate extents.

It then copies the chunk into its own file and calls SetEndOfFile to shrink the larger file (since the content is now in its own file).

I have tested this against a 1GB file broken into 100 pieces and it ran in less than 30 seconds. Furthermore, this should theoretically run in a space-efficient manner (not consuming more than the total file size plus the largest chunk size at any given time). I suspect there are performance improvements, but this is mostly a proof of concept.

0
ответ дан 7 December 2019 в 12:22
поделиться

Вы можете скопировать вторую часть файла в новый файл и затем обрезать исходный файл. При таком подходе вы копируете только половину файла.

0
ответ дан 7 December 2019 в 12:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: