>source

AWS S3 서버에서 이진 파일을 다운로드하기위한 코드를 작성하려고했습니다.

아래 코드를 작성했는데 ~ 200MB 바이너리 파일에 대해서는 괜찮은 것 같아서 제대로 작동한다고 생각했습니다.

그러나 200MB ~와 같은 큰 파일의 경우 파일의 앞부분 만 다운로드됩니다.

예를 들어 비디오 파일 (1.2GB)은 앞 부분 (460MB ~ 700MB) 만 다운로드했습니다.

이러한 이유는 무엇입니까? 비열한 기능에 관한 것입니까?

// 3. file download from s3
{
    string strTargetPath = hThis->m_strTargetPath;
    Aws::SDKOptions options;
    options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Trace;
    Aws::InitAPI(options);
    {
        // Download from s3 using GetObject
        char *bucket_name = "mybucket";
        std::string key_name = strTargetPath;
        Aws::Client::ClientConfiguration clientConfig;
        clientConfig.region = "ap-northeast-2";
        //Aws::S3::S3Client s3_client;
        std::unique_ptr< Aws::S3::S3Client > s3_client(new Aws::S3::S3Client(clientConfig));
        Aws::S3::Model::GetObjectRequest object_request;
        object_request.WithBucket(bucket_name).WithKey(key_name.c_str());
        // parse file name from path
        string str_arr[1000];
        int str_cnt = 0;
        char *str_buff = new char[1000];
        strcpy(str_buff, strTargetPath.c_str());
        char *tok = strtok(str_buff, "/");
        while (tok != nullptr) {
            str_arr[str_cnt++] = string(tok);
            tok = strtok(nullptr, "/");
        }
        string fileName = str_arr[str_cnt - 1];
        auto get_object_outcome = s3_client.get()->GetObject(object_request);
        if (get_object_outcome.IsSuccess())
        {
            Aws::OFStream local_file;
            std::string strFileName = fileName;
            hThis->m_origFileNameString = strFileName;
            hThis->m_origFileName = strFileName.c_str();
            // Writing file downloaded
            local_file.open(hThis->m_origFileName, std::ios::out | std::ios::binary);
            local_file << get_object_outcome.GetResult().GetBody().rdbuf();
            hThis->Logger(CPrePackagerDlg::currentDateTime() + "download is done\n");
            TCHAR programpath[_MAX_PATH];
            GetCurrentDirectory(_MAX_PATH, programpath);
            hThis->m_valOriginFolderPath.Format(_T("%s\\"), programpath);
            hThis->m_valOriginFolderPath += hThis->m_origFileName;
        }
        else
        {
            hThis->Logger(CPrePackagerDlg::currentDateTime() + "s3 download error: " +
                get_object_outcome.GetError().GetExceptionName() + " " +
                get_object_outcome.GetError().GetMessage() + "\n");
            hThis->runSignal = CPrePackagerDlg::RunSignal::STAT_RUN_STOP;
        }

    }
    Aws::ShutdownAPI(options);
}

  • 답변 # 1

    와이즈 비즈

    초기 예제에서 전체 파일을 메모리에 저장하기 때문입니다. 두 번째 코드 스 니펫에서는 fstream을 응답 스트림으로 사용하여 올바른 작업을 수행했습니다. 이제 디스크에 바로 씁니다.

  • 답변 # 2

    지금도 왜 작동하지 않는지 정확히 모르겠습니다.

    하지만 내 방법을 아래와 같이 변경했는데 작동했습니다.


    이 코드는 다운로드 된 청크 데이터가 디스크로 직접 전송되도록합니다.

    따라서 메모리를 많이 사용하지 않습니다. (약 10 ~ 30MB)

    Even now, I don't know exactly Why it doesn't work.

    // 3. file download from s3 { string strTargetPath = hThis->m_strTargetPath; Aws::SDKOptions options; options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Trace; Aws::InitAPI(options); { // Download from s3 using GetObject char *bucket_name = "nemodax-upload-dev"; std::string key_name = strTargetPath; Aws::Client::ClientConfiguration clientConfig; clientConfig.region = "ap-northeast-2"; //Aws::S3::S3Client s3_client; std::unique_ptr< Aws::S3::S3Client > s3_client(new Aws::S3::S3Client(clientConfig)); Aws::S3::Model::GetObjectRequest object_request; object_request.WithBucket(bucket_name).WithKey(key_name.c_str()); // parse file name from path string str_arr[1000]; int str_cnt = 0; char *str_buff = new char[1000]; strcpy(str_buff, strTargetPath.c_str()); char *tok = strtok(str_buff, "/"); while (tok != nullptr) { str_arr[str_cnt++] = string(tok); tok = strtok(nullptr, "/"); } string fileName = str_arr[str_cnt - 1]; // 다운로드하면서 스트림을 아래 fileName으로 지정하는 파일로 바로바로 저장 그래서 메모리를 별로 안먹는다. object_request.SetResponseStreamFactory( [=]() { //return Aws::New<Aws::FStream>("S3DOWNLOAD", hThis->m_origFileName, std::ios_base::out | std::ios_base::binary); return Aws::New<Aws::FStream>("S3DOWNLOAD", fileName, std::ios_base::out | std::ios_base::binary); } ); auto get_object_outcome = s3_client.get()->GetObject(object_request); if (get_object_outcome.IsSuccess()) { std::string strFileName = fileName; hThis->m_origFileNameString = strFileName; hThis->m_origFileName = strFileName.c_str(); hThis->Logger(CPrePackagerDlg::currentDateTime() + "file size: " + std::to_string(get_object_outcome.GetResult().GetContentLength()) + "\n"); hThis->Logger(CPrePackagerDlg::currentDateTime() + "download is done\n"); // 다운로드된 원본 파일 경로를 멤버변수로 등록-> 추후 암호화때 이 경로를 참조함. // 파일경로 + 파일명 조합 TCHAR programpath[_MAX_PATH]; GetCurrentDirectory(_MAX_PATH, programpath); hThis->m_valOriginFolderPath.Format(_T("%s\\"), programpath); hThis->m_valOriginFolderPath += hThis->m_origFileName; } else { hThis->Logger(CPrePackagerDlg::currentDateTime() + "s3 download error: " + get_object_outcome.GetError().GetExceptionName() + " " + get_object_outcome.GetError().GetMessage() + "\n"); hThis->runSignal = CPrePackagerDlg::RunSignal::STAT_RUN_STOP; } } Aws::ShutdownAPI(options); }

  • 이전 sql - 업데이트하지 않고 두 열 교환
  • 다음 dictionary - mapTree 함수 구현