답변:
MD5 알고리즘의 JS 구현 이 있지만 이전 브라우저는 일반적으로 로컬 파일 시스템에서 파일을 읽을 수 없습니다 .
2009 년에 썼습니다. 그렇다면 새 브라우저는 어떻습니까?
FileAPI 를 지원하는 브라우저를 사용하면 파일의 내용을 * 읽을 수 * 있습니다 . 사용자가 <input>
요소 또는 드래그 앤 드롭 으로 파일 을 선택해야합니다 . 2013 년 1 월 현재 주요 브라우저가 누적되는 방식은 다음과 같습니다.
대용량 파일을 효율적으로 해시하기 위해 증분 md5를 구현하는 라이브러리를 만들었습니다. 기본적으로 파일을 청크 단위로 읽고 (메모리를 낮게 유지하기 위해) 점진적으로 해시합니다. Readme에 기본적인 사용법과 예제가 있습니다.
HTML5 FileAPI가 필요하므로 확인해야합니다. 테스트 폴더에 전체 예제가 있습니다.
.end()
방법에 문제가있는 것 같습니다 . 이 메서드를 다시 호출하면 다음 번에 잘못된 결과를 제공합니다. 내부적으로 .end()
전화 하기 때문 .reset()
입니다. 이것은 코딩 재앙이며 라이브러리 작성에 좋지 않습니다.
CryptoJS 의 MD5 함수 와 HTML5 FileReader API를 사용하여 MD5 해시를 계산하는 것은 매우 쉽습니다 . 다음 코드 스 니펫은 바이너리 데이터를 읽고 브라우저로 드래그 한 이미지에서 MD5 해시를 계산하는 방법을 보여줍니다.
var holder = document.getElementById('holder');
holder.ondragover = function() {
return false;
};
holder.ondragend = function() {
return false;
};
holder.ondrop = function(event) {
event.preventDefault();
var file = event.dataTransfer.files[0];
var reader = new FileReader();
reader.onload = function(event) {
var binary = event.target.result;
var md5 = CryptoJS.MD5(binary).toString();
console.log(md5);
};
reader.readAsBinaryString(file);
};
드래그 앤 드롭 영역을 보려면 CSS를 추가하는 것이 좋습니다.
#holder {
border: 10px dashed #ccc;
width: 300px;
height: 300px;
}
#holder.hover {
border: 10px dashed #333;
}
끌어서 놓기 기능에 대한 자세한 내용은 여기에서 찾을 수 있습니다. File API 및 FileReader
Google Chrome 버전 32에서 샘플을 테스트했습니다.
readAsBinaryString()
표준화되지 않았고 Internet Explorer에서 지원되지 않는다는 것입니다. Edge에서 테스트하지는 않았지만 IE11에서도 지원하지 않습니다.
readAsBinaryString()
. caniuse.com/#feat=filereader — Microsoft Edge에서 지원합니다.
readAsBinaryString()
이전 브라우저에서는 지원하지 않으므로 주의해야한다는 점을 지적하고 싶었습니다 . 내가 찾은 대안은 SparkMD5입니다. FileReader API도 사용하지만 readAsArrayBuffer
IE에서 지원 하는 메서드를 사용합니다 . 그리고 대용량 파일을 청크로 읽어서 처리 할 수 있습니다.
CryptoJS.lib.WordArray.create(arrayBuffer);
spark-md5
및Q
HTML5 파일 API를 지원하는 최신 브라우저를 사용한다고 가정하면 다음 은 대용량 파일 의 MD5 해시 를 계산하는 방법입니다 (가변 청크에 대한 해시를 계산합니다).
function calculateMD5Hash(file, bufferSize) {
var def = Q.defer();
var fileReader = new FileReader();
var fileSlicer = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
var hashAlgorithm = new SparkMD5();
var totalParts = Math.ceil(file.size / bufferSize);
var currentPart = 0;
var startTime = new Date().getTime();
fileReader.onload = function(e) {
currentPart += 1;
def.notify({
currentPart: currentPart,
totalParts: totalParts
});
var buffer = e.target.result;
hashAlgorithm.appendBinary(buffer);
if (currentPart < totalParts) {
processNextPart();
return;
}
def.resolve({
hashResult: hashAlgorithm.end(),
duration: new Date().getTime() - startTime
});
};
fileReader.onerror = function(e) {
def.reject(e);
};
function processNextPart() {
var start = currentPart * bufferSize;
var end = Math.min(start + bufferSize, file.size);
fileReader.readAsBinaryString(fileSlicer.call(file, start, end));
}
processNextPart();
return def.promise;
}
function calculate() {
var input = document.getElementById('file');
if (!input.files.length) {
return;
}
var file = input.files[0];
var bufferSize = Math.pow(1024, 2) * 10; // 10MB
calculateMD5Hash(file, bufferSize).then(
function(result) {
// Success
console.log(result);
},
function(err) {
// There was an error,
},
function(progress) {
// We get notified of the progress as it is executed
console.log(progress.currentPart, 'of', progress.totalParts, 'Total bytes:', progress.currentPart * bufferSize, 'of', progress.totalParts * bufferSize);
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/q.js/1.4.1/q.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/spark-md5/2.0.2/spark-md5.min.js"></script>
<div>
<input type="file" id="file"/>
<input type="button" onclick="calculate();" value="Calculate" class="btn primary" />
</div>
FileAPI를 사용해야합니다. 최신 FF 및 Chrome에서는 사용할 수 있지만 IE9에서는 사용할 수 없습니다. 위에서 제안한 md5 JS 구현을 가져옵니다. 나는 이것을 시도하고 JS가 너무 느리기 때문에 포기했습니다 (큰 이미지 파일의 경우 몇 분). 누군가 유형 배열을 사용하여 MD5를 다시 작성하면 다시 방문 할 수 있습니다.
코드는 다음과 같습니다.
HTML:
<input type="file" id="file-dialog" multiple="true" accept="image/*">
JS (w JQuery)
$("#file-dialog").change(function() {
handleFiles(this.files);
});
function handleFiles(files) {
for (var i=0; i<files.length; i++) {
var reader = new FileReader();
reader.onload = function() {
var md5 = binl_md5(reader.result, reader.result.length);
console.log("MD5 is " + md5);
};
reader.onerror = function() {
console.error("Could not read the file");
};
reader.readAsBinaryString(files.item(i));
}
}
reader
변수는 onload 함수가 실행될 때 마지막 파일이됩니다.
CryptoJS.lib.WordArray.create(arrayBuffer);
JS에서 파일 시스템 액세스를 얻을 수 없다는 점을 제외하고는 클라이언트가 생성 한 체크섬을 전혀 신뢰하지 않습니다. 따라서 서버에서 체크섬을 생성하는 것은 어떤 경우에도 필수입니다. – Tomalak 2009 년 4 월 20 일 14:05
대부분의 경우 쓸모가 없습니다. 클라이언트 측에서 MD5를 계산하여 서버 측에서 재 계산 된 코드와 비교하여 서로 다른 경우 업로드가 잘못되었다고 결론을 내릴 수 있습니다. 나는 손상되지 않은 파일을받는 것이 중요한 과학 데이터의 대용량 파일로 작업하는 응용 프로그램에서이를 수행해야했습니다. 제 경우는 간단했습니다. 사용자는 이미 데이터 분석 도구에서 MD5를 계산했기 때문에 텍스트 필드로 요청하면되었습니다.
파일의 해시를 얻으려면 많은 옵션이 있습니다. 일반적으로 문제는 큰 파일의 해시를 가져 오는 것이 정말 느리다는 것입니다.
파일의 시작 부분이 64kb이고 끝 부분이 64kb 인 파일 해시를 가져 오는 작은 라이브러리를 만들었습니다.
라이브 예 : http://marcu87.github.com/hashme/ 및 라이브러리 : https://github.com/marcu87/hashme
인터넷에 MD5 해시를 만드는 스크립트가 몇 개 있습니다.
webtoolkit의 것이 좋습니다. http://www.webtoolkit.info/javascript-md5.html
그러나 액세스가 제한되어 있기 때문에 로컬 파일 시스템에 대한 액세스 권한이 있다고 생각하지 않습니다.
지금까지 좋은 해결책을 찾았기를 바랍니다. 그렇지 않은 경우 아래 솔루션은 js-spark-md5를 기반으로하는 ES6 약속 구현입니다.
import SparkMD5 from 'spark-md5';
// Read in chunks of 2MB
const CHUCK_SIZE = 2097152;
/**
* Incrementally calculate checksum of a given file based on MD5 algorithm
*/
export const checksum = (file) =>
new Promise((resolve, reject) => {
let currentChunk = 0;
const chunks = Math.ceil(file.size / CHUCK_SIZE);
const blobSlice =
File.prototype.slice ||
File.prototype.mozSlice ||
File.prototype.webkitSlice;
const spark = new SparkMD5.ArrayBuffer();
const fileReader = new FileReader();
const loadNext = () => {
const start = currentChunk * CHUCK_SIZE;
const end =
start + CHUCK_SIZE >= file.size ? file.size : start + CHUCK_SIZE;
// Selectively read the file and only store part of it in memory.
// This allows client-side applications to process huge files without the need for huge memory
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
};
fileReader.onload = e => {
spark.append(e.target.result);
currentChunk++;
if (currentChunk < chunks) loadNext();
else resolve(spark.end());
};
fileReader.onerror = () => {
return reject('Calculating file checksum failed');
};
loadNext();
});
다음 스 니펫은 파일을 읽고 해싱하는 동안 400MB / s의 처리량을 보관할 수있는 예를 보여줍니다.
WebAssembly 를 기반으로하며 js 전용 라이브러리보다 빠르게 해시를 계산하는 hash -wasm 이라는 라이브러리를 사용하고 있습니다 . 2020 년부터 모든 최신 브라우저는 WebAssembly를 지원합니다.
const chunkSize = 64 * 1024 * 1024;
const fileReader = new FileReader();
let hasher = null;
function hashChunk(chunk) {
return new Promise((resolve, reject) => {
fileReader.onload = async(e) => {
const view = new Uint8Array(e.target.result);
hasher.update(view);
resolve();
};
fileReader.readAsArrayBuffer(chunk);
});
}
const readFile = async(file) => {
if (hasher) {
hasher.init();
} else {
hasher = await hashwasm.createMD5();
}
const chunkNumber = Math.floor(file.size / chunkSize);
for (let i = 0; i <= chunkNumber; i++) {
const chunk = file.slice(
chunkSize * i,
Math.min(chunkSize * (i + 1), file.size)
);
await hashChunk(chunk);
}
const hash = hasher.digest();
return Promise.resolve(hash);
};
const fileSelector = document.getElementById("file-input");
const resultElement = document.getElementById("result");
fileSelector.addEventListener("change", async(event) => {
const file = event.target.files[0];
resultElement.innerHTML = "Loading...";
const start = Date.now();
const hash = await readFile(file);
const end = Date.now();
const duration = end - start;
const fileSizeMB = file.size / 1024 / 1024;
const throughput = fileSizeMB / (duration / 1000);
resultElement.innerHTML = `
Hash: ${hash}<br>
Duration: ${duration} ms<br>
Throughput: ${throughput.toFixed(2)} MB/s
`;
});
<script src="https://cdn.jsdelivr.net/npm/hash-wasm"></script>
<!-- defines the global `hashwasm` variable -->
<input type="file" id="file-input">
<div id="result"></div>
현재 HTML5를 사용하면 바이너리 파일의 md5 해시를 계산할 수 있지만 그 이전 단계는 banary 데이터 BlobBuilder를 문자열로 변환하는 것이라고 생각합니다.이 단계를 수행하려고하지만 성공하지 못했습니다.
내가 시도한 코드는 다음과 같습니다. HTML5 Javascript에서 BlobBuilder를 문자열로 변환