본문 바로가기

공부방/Flex

[Flex] 대용량 파일 전송

Flex에서 소켓을 통한 파일 전송은 100메가 용량만 신뢰성을 보장한다는 내용의 글을 본적이 있다.

현재 진행하고 있는 프로젝트에서 대용량의 파일 전송이 요구되어 이를 위해 대용량의 파일을 100메가로 분할 하여 전송하는 방법을 사용하여 문제를 해결 하였다.

아직 잘 다듬어 지진 않았지만 테스트를 위해 사용한 내용을 정리한다.



1. 먼저 파일 브라우저에서 여러개의 파일을 선택하기 위한 부분 구현이다.

public var _numCurrentUpload:Number = 0;  // 파일 인덱스
public var filePosion:uint = 0;  // 분할하여 전송중인 파일의 포지션
public var currentFileSize:uint = 0;  // 전체 파일중 전송 된 파일의 용량
public var currentFileTotalSize:uint = 0;  // 파일 크기 외에 파일 이름등이 포함된 크기의 용량

public var _refUploadFile:FileStream;  // 파일 리스트 사용을 위한 파일 레퍼런스
public var _refUploadFiles:File;  // 업로드 할 파일 
public var _arrUploadFiles:Array;  // 업로드할 파일 리스트

// 파일 브라우저에 비디오 파일을 위한 필터를 적용 및 멀티 파일 브라우저 적용
public function addFiles():void {
        var _refFilter:FileFilter = new FileFilter("Video(*.flv, *.mp4 , *.3gp)", "*.flv;*.mp4;*.3gp");
_refUploadFiles = new File();
_refUploadFiles.addEventListener(FileListEvent.SELECT_MULTIPLE, onSelectFile);
_refUploadFiles.browseForOpenMultiple("Select Files", [_refFilter]);
}

// 파일 브라우저에서 파일 선택 시 호출 (파일 리스트에 선택한 파일들을 등록한다)
public function onSelectFile(event:FileListEvent):void 
{
var arrFoundList:Array = new Array();
for (var i:Number = 0; i < _arrUploadFiles.length; i++) {
for (var j:Number = 0; j < event.files.length; j++) {
if (_arrUploadFiles[i].name == event.files[j].name) {
arrFoundList.push(event.files[j].name);
event.files.splice(j, 1);
j--;
}
}
}
if (event.files.length >= 1) {
for (var k:Number = 0; k < event.files.length; k++) {
var flag:Boolean = new Boolean(true);
_arrUploadFiles.push({
name:event.files[k].name,
size:formatFileSize(event.files[k].size),
file:event.files[k],
flag:flag});
}
listFiles.dataProvider = _arrUploadFiles;
listFiles.selectedIndex = _arrUploadFiles.length - 1;
}
if (arrFoundList.length >= 1) {
Alert.show("The file(s): \n\n• " + arrFoundList.join("\n• ") + "\n\n...are already on the upload list. Please change the filename(s) or pick a different file.", "File(s) already on list");
}

// 파일 목록에 추가된 파일 삭제
public function removeFiles():void {
var arrSelected:Array = listFiles.selectedIndices;
if (arrSelected.length >= 1) {
for (var i:Number = 0; i < arrSelected.length; i++) {
_arrUploadFiles[Number(arrSelected[i])] = null;
}
for (var j:Number = 0; j < _arrUploadFiles.length; j++) {
if (_arrUploadFiles[j] == null) {
_arrUploadFiles.splice(j, 1);
j--;
if(_numCurrentUpload > 0){
_numCurrentUpload--;
}
}
}
listFiles.dataProvider = _arrUploadFiles;
listFiles.selectedIndex = 0;
}
trace(_numCurrentUpload);
}

// 추가된 파일의 용량 표시
public function formatFileSize(numSize:Number):String {
var strReturn:String;
numSize = Number(numSize / 1000);
strReturn = String(numSize.toFixed(1) + " KB");
if (numSize > 1000) {
numSize = numSize / 1000;
strReturn = String(numSize.toFixed(1) + " MB");
if (numSize > 1000) {
numSize = numSize / 1000;
strReturn = String(numSize.toFixed(1) + " GB");
}
}
return strReturn;
}

2. 전송 버튼 클릭 시 파일 전송

//전송 버튼 클릭 시 파일 리스트에 있는 파일 들 전송 
public function startUpload(booIsFirst:Boolean):void 
{
if (_arrUploadFiles.length > 0 && _arrUploadFiles.length > _numCurrentUpload ) {
if(_arrUploadFiles[_numCurrentUpload].flag){
_refUploadFile = new FileStream();
_refUploadFile.open(_arrUploadFiles[_numCurrentUpload].file ,FileMode.READ);
sendCurrentFile(true);
}
}
}

// 파일 리스트의 현재 파일 전송 (반복문을 돌면서 리스트에 있는 파일들을 하나씩 전송)
public function sendCurrentFile(boolean:Boolean):void{
var temp:ByteArray = new ByteArray();
if(boolean){
if(filePosion == 0){
if(_arrUploadFiles[_numCurrentUpload].file.size > maxLength){
_refUploadFile.readBytes(temp, 0, maxLength);
filePosion = filePosion + maxLength;
}else{
_refUploadFile.readBytes(temp, 0, _refUploadFile.bytesAvailable);
}
sendFile(temp,_arrUploadFiles[_numCurrentUpload].file, firstFlag);
}else{
if(_refUploadFile.bytesAvailable > maxLength){
_refUploadFile.position = filePosion;
_refUploadFile.readBytes(temp, 0, maxLength);
filePosion = filePosion + maxLength;
}else{
_refUploadFile.position = filePosion;
_refUploadFile.readBytes(temp, 0, _refUploadFile.bytesAvailable);
}
sendFIle(temp,_arrUploadFiles[_numCurrentUpload].file, firstFlag);
}
}else{
trace();
}
}


3. 소켓을 통한 파일 전송 부분


// 비디오 파일 전송

public function sendFile(dt:ByteArray, uploadFile:File, firstFlag:Boolean):void{

if(m_socket.connected == true)

{

var data:ByteArray = new ByteArray();  //Data 정보 담는 배열

var tempData:ByteArray = new ByteArray(); // 임시 배열 

m_socket.writeMultiByte("xxx","ASCII");  // 1 . 소켓에 플래그 저장 (3byte)

tempData.writeUTFBytes(uploadFile.name);   

data.writeUnsignedInt(tempData.length);  // 파일이름 크기 갱신

data.writeBytes(tempData, 0, tempData.length); // 파일 이름 갱신

tempData.clear();

data.writeUnsignedInt(uploadFile.size);  // 현재 데이터 크기 저장(4바이트)

data.writeBytes(dt, 0, dt.bytesAvailable); // 소켓에 데이터 저장

m_socket.writeUnsignedInt(data.length);  // 소켓에 데이터 크기 저장


m_socket.writeUnsignedInt(McsCMD.CMD_SND_MOV);   // 소켓에 커맨드 저장 (4byte)

m_socket.writeBytes(data, 0 , data.length); // 소켓에 데이터 저장

if (firstFlag){  

v_filemanager.currentFileTotalSize = getFileSize(uploadFile.size ,m_socket.bytesPending, dt.length); v_filemanager.firstFlag = false;

}

v_filemanager.currentFileSize = v_filemanager.currentFileSize + m_socket.bytesPending;

m_socket.flush();

}else{

Alert.show("대상에 연결되어있지 않습니다.", "확인");

}

}