2015-05-02 1 views
5

Я хочу разрешить пользователям перетаскивать изображения со своего рабочего стола в окно браузера, а затем загружать эти изображения на сервер. Я хочу загружать каждый файл только один раз, даже если он выпал в окне несколько раз. По соображениям безопасности информация из объекта File, доступная для JavaScript, ограничена. В соответствии с msdn.microsoft.com следующие свойства могут быть только для чтения:Обнаружение, если пользователь дважды удаляет один и тот же файл в окне браузера

  • name
  • lastModifiedDate

(Сафари также подвергает size и type).

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

Я создал сценарий, который читает в необработанном dataURL каждого файла изображения и сравнивает его с файлами, которые ранее были отброшены в окне. Одним из преимуществ этого является то, что он может обнаруживать идентичные файлы с разными именами.

Это работает, но кажется излишним. Он также требует огромного объема данных для хранения. Я мог бы улучшить это (и добавить к overkill), сделав хэш данныхURL и сохранив это вместо этого.

Я надеюсь, что может быть более элегантный способ достижения моей цели. Что вы можете предложить?

<!DOCTYPE html> 
<html> 
<head> 
    <title>Detect duplicate drops</title> 
    <style> 
html, body { 
width: 100%; 
height: 100%; 
margin: 0; 
background: #000; 
} 
    </style> 
    <script> 
var body 
var imageData = [] 


document.addEventListener('DOMContentLoaded', function ready() { 
    body = document.getElementsByTagName("body")[0] 
    body.addEventListener("dragover", swallowEvent, false) 
    body.addEventListener("drop", treatDrop, false) 
}, false) 


function swallowEvent(event) { 
    // Prevent browser from loading the dropped image in an empty page 
    event.preventDefault() 
    event.stopPropagation() 
} 


function treatDrop(event) { 
    swallowEvent(event) 

    for (var ii=0, file; file = event.dataTransfer.files[ii]; ii++) { 
    importImage(file) 
    } 
} 


function importImage(file) { 
    var reader = new FileReader() 

    reader.onload = function fileImported(event) { 
     var dataURL = event.target.result 
     var index = imageData.indexOf(dataURL) 
     var img, message 

     if (index < 0) { 
      index = imageData.length 
      console.log(dataURL) 
      imageData.push(dataURL, file.name) 
      message = "Image "+file.name+" imported" 
     } else { 
      message = "Image "+file.name+" imported as "+imageData[index+1] 
     } 

     img = document.createElement("img") 
     img.src = imageData[index] // copy or reference? 
     body.appendChild(img) 

     console.log(message) 
    } 

    reader.readAsDataURL(file) 
} 
    </script> 
</head> 
<body> 
</body> 
</html> 
+0

Я предлагаю разрешить пользователю загружать изображения без разбора (с некоторыми JS, чтобы убедиться, что они на самом деле являются изображениями). Тогда на стороне сервера вы будете делать интенсивные операции с ЦП и сравнивать файлы, чтобы убедиться, что они идентичны ... если они есть, отверните одно из изображений и сообщите об этом пользователю. Если нет, хэш их имена и сохранить их – Literphor

+0

Спасибо за ваше предложение @Literphor. Однако в этом конкретном случае важно, чтобы на каждом изображении была только одна клиентская копия. –

+0

'file.size' хорошо поддерживается, поэтому вы можете снизить коэффициенты больше без обработки файлов. – dandavis

ответ

0

Вот предложение (я не видел упоминания в вашем вопросе):

Создать Blob URL для каждого file -объекта в FileList -объекте, сохраняемой в браузерах URL Store, сохраняя их URL-строку.

Затем вы проходите, что URL-строку в webworker (отдельного поток), который использует FileReader читать каждый файл (доступ через строку Blob URL) в фрагментированных секциях, повторное использованием один буфера фиксированного размера (почти как круговой буфер), чтобы вычислить хэш файла (есть простые/быстрые переносимые хэши, такие как crc32, которые часто можно просто комбинировать с вертикальной и горизонтальной контрольной суммой в одном и том же цикле (также переносимые куски) ,
Вы можете ускорить процесс, прочитав 32-разрядные (без знака) значения вместо 8-битных значений, используя соответствующий «bufferview» (это в 4 раза быстрее). Системная сущность не важна, не тратьте ресурсы на это!

По завершении веб-работник затем передает хэш файла в основное приложение/приложение, которое затем просто выполняет сравнение ваших матриц [[fname, fsize, blobUrl, fhash] /* , etc /*].

Pro
Фиксированный буфер повторно используются значительно снижает использование памяти (на любой уровень вы укажете), то WebWorker поднимает производительность, используя дополнительный поток (который не блокирует нить вашего основного браузера) ,

Con
Вы все еще нужен сторона сервер откат для браузеров с Отключено JavaScript (вы можете добавить скрытое поле в форму и установить его значение, используя JavaScript в качестве помощи JavaScript-включена проверки, чтобы более низкая загрузка на стороне сервера). Однако .. даже тогда .. вам все равно потребуется резервное копирование на стороне сервера для защиты от вредоносного ввода.

Полезность
Итак, нет чистой прибыли? Ну .. если вероятность того, что пользователь может загружать дубликаты файлов (или просто использует их в веб-приложении), чем вы сохранили на талии, чтобы просто выполнить чек. Это довольно (экологическая/финансовая) победа в моей книге.


Дополнительные
Хэши склонны к столкновению, период. Чтобы снизить (реалистичную) вероятность столкновения, вы должны выбрать более продвинутый хеш-алго (большинство из них легко переносится в режиме chunked). Очевидный компромисс для более продвинутых хэшей - это более высокий размер кода и более низкая скорость (более высокая загрузка ЦП).

Смежные вопросы