2016-01-29 2 views
1

Я работаю с большим количеством очень больших файлов (например, 1000 x 512 МБ), и я реализовал способ ускорить работу, записав определенную информацию в базы данных, к которым можно получить доступ когда я снова запускаю программное обеспечение. По этой причине мне нужно иметь возможность генерировать уникальные имена файлов для произвольных подмножеств этих файлов.Python: создание уникального имени файла для списка файлов

Я попытался сгенерировать имена файлов в зависимости от общего размера файла в подмножестве, даты изменения файла и даже их комбинаций. Проблема в том, что многие файлы имеют одинаковый размер и ту же самую дату изменения, что делает мою текущую строку идентификатора неоднозначной. Важно только то, что для одного и того же списка файлов идентификатор всегда одинаков, поэтому я всегда могу получить доступ к правильному файлу для тех же файлов. Любые идеи приветствуются!

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

import os 
import glob 
import datetime 

file_paths = glob.glob("path/to/files/*.foo") 

def modification_date(file_path): 
    return datetime.datetime.fromtimestamp(os.path.getmtime(filename=file_path)) 

uid = [modification_date(f) for f in file_paths] 
uid = [d.year + d.day + d.day + d.hour + d.minute + d.second for d in uid] 
uid = sum(uid) // len(uid) + sum([os.path.getsize(f) for f in file_paths]) 
+1

Если все метаданные (размер, дата модификации) одинаковы, вам необходимо использовать содержимое файла. Простой md5 хэш может сделать. – Selcuk

+0

У этих файлов есть имена? Можете ли вы указать свое имя подмножества в комбинации этих имен файлов? ех. Подмножество, состоящее из «foo.txt» и «bar.exe», называется '' (foo.txt) (bar.exe) ". – Kevin

+0

@Kevin Я также подумал об использовании имен файлов, но они довольно длинные, и у меня будет очень длинный уникальный идентификатор. Возможно, есть быстрый способ конвертировать все имена файлов в последовательность чисел ... имена файлов содержат всевозможные буквы и символы, хотя ... – HansSnah

ответ

1

Это может быть дико, но до тех пор, как файлы, включенные в список не меняется, вы могли бы получить то, что вы после этого с hashlib?

import hashlib, glob 
file_paths = glob.glob("/home/rolf/StackOverflow/*.py") 
hash_object = hashlib.sha256(str(file_paths)) 
file_name= hash_object.hexdigest() 
file_name 
'f69dd9583eabae55319e9a56dbfc737cc16ab58634d9042f4c530e9a85e7d77c' 

file_paths = glob.glob("/home/rolf/Research/*.py") 
hash_object = hashlib.sha256(str(file_paths)) 
file_name= hash_object.hexdigest() 
file_name 
'dc4beec8e859b190d966068a52674d135f22520514ac1020b3e11a4af090e579' 
+1

Хммм. Это работает, но как я могу быть уверен, что это уникально для всех потенциальных комбинаций? – HansSnah

+0

Как утверждает Майкл Маллани в прилагаемой ссылке, вероятность столкновения между двумя входами зависит исключительно от количества входов и равна 1 - (2^256)!/((2^256^inputcount) * (2^256-inputcount)!), В основном нуль для разумного количества входов. http://stackoverflow.com/questions/2299846/are-there-circumstances-where-a-hash-algorithm-can-be-guaranteed-unique –

+0

Хорошо, я реализую это решение: D Спасибо! – HansSnah

0

Если главный список всех файлов никогда не изменяется, то вы можете однозначно закодировать любое подмножество этого списка в строку около len(master_list)/8 символов. Во-первых, вы создаете бит-массив, где 0 в индексе i означает, что «i-й элемент главного списка не является частью этого подмножества», а 1 означает, что «i-й элемент основного списка является частью этого подмножества». Затем вы преобразовываете массив бит в целое число, которое затем можно упаковать в строку.

import struct 
import base64 

#encodes a positive integer of any size into a string. 
def string_from_int(value): 
    bytes = [] 
    while value > 0: 
     bytes.append(value % 2**8) 
     value >>= 8 
    return struct.pack("i"*len(bytes), *bytes) 

#decodes a string into a positive integer. Only works on strings whose length is divisible by 4. 
def int_from_string(s): 
    bytes = struct.unpack("i" * (len(s)/4), s) 
    return sum(byte * (256**i) for i, byte in enumerate(bytes)) 

#encodes a subset of a list into a filename-safe string. 
def encode(master_file_list, subset): 
    bitmask = [int(filename in subset) for filename in master_file_list] 
    int_value = sum(bit*2**(i) for i, bit in enumerate(bitmask)) 
    string_value = string_from_int(int_value) 
    #the string may contain slashes or other characters illegal in filenames, so we b64 endoce it, at the expense of increasing the length by %20 or so 
    return base64.urlsafe_b64encode(string_value) 

#the reverse of `encode`. 
def decode(master_file_list, filename): 
    string_value = base64.urlsafe_b64decode(filename) 
    int_value = int_from_string(string_value) 
    subset = [value for i,value in enumerate(master_file_list) if (2**i) & int_value] 
    return subset 

master_file_list = ['caddy.jpg', 'fjeld.dat', 'gyve.ini', 'karts.png', 'laves.txt', 'nimbi.jpg', 'ocas.ini', 'sipes.dat', 'wacky.png', 'waff.png'] 
subset = ["fjeld.dat", "laves.txt", "ocas.ini"] 
filename = encode(master_file_list, subset) 
print "Subset is:", subset 
print "Filename is:", filename 
print "Filename decodes back to:", decode(master_file_list, filename) 

Результат:

Subset is: ['fjeld.dat', 'laves.txt', 'ocas.ini'] 
Filename is: UgAAAA== 
Filename decodes back to: ['fjeld.dat', 'laves.txt', 'ocas.ini'] 
Смежные вопросы