본문 바로가기
UnrealEngine

[UE] 파일 관리 시스템

by 공작사 2023. 8. 14.

언리얼로 파일 관리 시스템을 만들었다.

업로드 중

좌측은 폴더 뷰어, 우측은 파일 뷰어다. 하단의 버튼은 좌측부터 폴더 삭제, 폴더 이름변경, 폴더 추가, 파일 복사, 파일 삭제, 파일 이름변경, 파일 업로드이다.

업로드 후

1. 파일 업로드

해당 기능을 위해 winAPI를 사용했다.

이전 포스팅인 CopyFileEx 을 사용해 업로드 진행 상황을 표시한다.

주의할 점은 콜백 함수를 전역함수로 해야한다. 멤버 함수로 만들면 랜더링 쓰레드가 멈춘다.

.hpp

더보기
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/Button.h"
#include "Components/TextBlock.h"

#include "UploadFile.generated.h"

class UFileUpload_Thread;
class ULibraryManager;

UCLASS()
class LOADSCENEPLUGIN_API UUploadFile : public UUserWidget
{
	GENERATED_BODY()
public:
	UUploadFile(const FObjectInitializer& obj);

	virtual void NativeConstruct() override;
	virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;

	UFUNCTION()
		void OnClicked_Btn_Yes();
	UFUNCTION()
		void OnClicked_Btn_No();
	UFUNCTION()
		void OnVisibilityChanged_UploadFile(ESlateVisibility InVisibility);
	void FileUploading();
	UFUNCTION()
		void ReloadFileList();

	UPROPERTY(meta = (bindwidget))
		UButton* Btn_Yes;
	UPROPERTY(meta = (bindwidget))
		UButton* Btn_No;
	UPROPERTY(meta = (bindwidget))
		UTextBlock* Text_doing;
	UPROPERTY(meta = (bindwidget))
		UTextBlock* Text_finish;
	UPROPERTY(meta = (bindwidget))
		UTextBlock* Text_Filename;

	TArray<FString> FileNames;
	UPROPERTY(BlueprintReadWrite)
		FString mFilename;
	UPROPERTY(BlueprintReadWrite)
		float nProgress;
	UPROPERTY(BlueprintReadWrite)
		int32 TotalFileCount;
	UPROPERTY(BlueprintReadWrite)
		int32 FileCount;
	int32 bCancel;

	UFileUpload_Thread* Thread;
	ULibraryManager* parent;
};

.cpp

더보기
// Fill out your copyright notice in the Description page of Project Settings.


#include "UploadFile.h"

#include "Windows/AllowWindowsPlatformTypes.h"
#include <windows.h>
#include "Windows/HideWindowsPlatformTypes.h"

#include "FileUpload_Thread.h"
#include "LibraryManager.h"
#include "MyExpandableArea.h"

#include "Kismet/KismetSystemLibrary.h"

DWORD CALLBACK CopyFile_Callback(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize,
	LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData);

UUploadFile::UUploadFile(const FObjectInitializer& obj) : Super(obj), bCancel(0)
{

}

void UUploadFile::NativeConstruct()
{
	Super::NativeConstruct();

	parent = Cast<ULibraryManager>(GetParent()->GetOuter()->GetOuter());

	OnVisibilityChanged.AddDynamic(this, &UUploadFile::OnVisibilityChanged_UploadFile);
	Btn_Yes->OnClicked.AddDynamic(this, &UUploadFile::OnClicked_Btn_Yes);
	Btn_No->OnClicked.AddDynamic(this, &UUploadFile::OnClicked_Btn_No);
	Btn_Yes->SetVisibility(ESlateVisibility::Collapsed);
	Btn_No->SetVisibility(ESlateVisibility::Collapsed);
	Text_doing->SetVisibility(ESlateVisibility::Collapsed);
	Text_finish->SetVisibility(ESlateVisibility::Collapsed);
}

void UUploadFile::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
	if (nProgress >= 1 && Btn_Yes->GetVisibility() != ESlateVisibility::Visible)
	{
		Btn_Yes->SetVisibility(ESlateVisibility::Visible);
		Btn_No->SetVisibility(ESlateVisibility::Collapsed);
		Text_doing->SetVisibility(ESlateVisibility::Collapsed);
		Text_finish->SetVisibility(ESlateVisibility::Visible);
	}
	else if (nProgress < 1 && Btn_No->GetVisibility() != ESlateVisibility::Visible)
	{
		Btn_Yes->SetVisibility(ESlateVisibility::Collapsed);
		Btn_No->SetVisibility(ESlateVisibility::Visible);
		Text_doing->SetVisibility(ESlateVisibility::Visible);
		Text_finish->SetVisibility(ESlateVisibility::Collapsed);
	}
}

void UUploadFile::OnClicked_Btn_Yes()
{
	ReloadFileList();

	SetVisibility(ESlateVisibility::Collapsed);
}

void UUploadFile::OnClicked_Btn_No()
{
	bCancel = 1;

	//취소된 파일이 삭제되길 기다림.(임의의 시간동안.)
	UKismetSystemLibrary::K2_SetTimer(this, FString(TEXT("ReloadFileList")), 1.0f, false);

	SetVisibility(ESlateVisibility::Collapsed);
}

void UUploadFile::OnVisibilityChanged_UploadFile(ESlateVisibility InVisibility)
{
	if (InVisibility == ESlateVisibility::Visible)
	{
		Thread = new UFileUpload_Thread(this);
	}
}

void UUploadFile::FileUploading()
{
	nProgress = 0.f;
	bCancel = 0;

	FileCount = 0;
	TotalFileCount = FileNames.Num();

	for (auto Filename : FileNames)
	{
		FString src = Filename;
		int32 index = 0;
		src.FindLastChar('/', index);
		FString temp = src.RightChop(index);

		FString Dest = parent->ClickedDir->_path + temp;
		GEngine->AddOnScreenDebugMessage(-1, 100, FColor::Magenta, Dest);

		//'/'제거 후 표시.
		mFilename = temp.RightChop(1);

		CopyFileEx(*src, *Dest, CopyFile_Callback, this, &bCancel, COPY_FILE_FAIL_IF_EXISTS);
	}
}

void UUploadFile::ReloadFileList()
{
	//새로고침
	FString temp = parent->ClickedDir->_path;
	parent->FindFiles(temp);
}

DWORD CALLBACK CopyFile_Callback(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred,
	DWORD dwStreamNumber, DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData)
{
	float pos = (double)TotalBytesTransferred.QuadPart / TotalFileSize.QuadPart;

	((UUploadFile*)lpData)->nProgress = pos;

	//GEngine->AddOnScreenDebugMessage(-1, 100, FColor::Magenta, FString::Printf(TEXT("TotalFileSize : %lld"), TotalFileSize.QuadPart));
	UE_LOG(LogTemp, Log, TEXT("TotalFileSize : %lld"), TotalFileSize.QuadPart);


	// 100 퍼센트 전송되지 않을 때
	if (pos < 1)
		return PROGRESS_CONTINUE;

	((UUploadFile*)lpData)->FileCount++;
	return PROGRESS_QUIET;
}

 

 

끝.

댓글