欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java視頻斷點(diǎn)上傳的實(shí)現(xiàn)示例

 更新時(shí)間:2024年05月08日 09:11:16   作者:拉普蘭德做的到嗎?  
斷點(diǎn)續(xù)傳指的是在下載或上傳時(shí),將下載或上傳任務(wù)人為的劃分為幾個(gè)部分,本文主要介紹了Java視頻斷點(diǎn)上傳的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下

什么是斷點(diǎn)續(xù)傳

通常視頻文件都比較大,所以對(duì)于媒資系統(tǒng)上傳文件的需求要滿足大文件的上傳要求。http協(xié)議本身對(duì)上傳文件大小沒有限制,但是客戶的網(wǎng)絡(luò)環(huán)境質(zhì)量、電腦硬件環(huán)境等參差不齊,如果一個(gè)大文件快上傳完了網(wǎng)斷了沒有上傳完成,需要客戶重新上傳,用戶體驗(yàn)非常差,所以對(duì)于大文件上傳的要求最基本的是斷點(diǎn)續(xù)傳。

什么是斷點(diǎn)續(xù)傳:

引用百度百科:斷點(diǎn)續(xù)傳指的是在下載或上傳時(shí),將下載或上傳任務(wù)(一個(gè)文件或一個(gè)壓縮包)人為的劃分為幾個(gè)部分,每一個(gè)部分采用一個(gè)線程進(jìn)行上傳或下載,如果碰到網(wǎng)絡(luò)故障,可以從已經(jīng)上傳或下載的部分開始繼續(xù)上傳下載未完成的部分,而沒有必要從頭開始上傳下載,斷點(diǎn)續(xù)傳可以提高節(jié)省操作時(shí)間,提高用戶體驗(yàn)性。

斷點(diǎn)續(xù)傳流程如下圖:

流程如下:

1、前端上傳前先把文件分成塊

2、一塊一塊的上傳,上傳中斷后重新上傳,已上傳的分塊則不用再上傳

3、各分塊上傳完成最后在服務(wù)端合并文件

 文件分塊

文件分塊的流程如下:

1、獲取源文件長(zhǎng)度

2、根據(jù)設(shè)定的分塊文件的大小計(jì)算出塊數(shù)

3、從源文件讀數(shù)據(jù)依次向每一個(gè)塊文件寫數(shù)據(jù)。

/**
     * 文件分塊上傳測(cè)試
     */
    @Test
    public  void  testChunk(){
        //獲取源文件
        File sourceFile = new File("B:\\workspace\\test\\you.ncm");
        //源文件字節(jié)大小
        long length = sourceFile.length();
        //分塊文件目錄
        String chunkPath="B:\\workspace\\test\\chunk\\";
        File chunkFolder = new File(chunkPath);
        //檢查目錄是否存在
        if (!chunkFolder.exists()) {
            //不存在就創(chuàng)建
            chunkFolder.mkdirs();
        }
        //分塊大小
        long chunkSize = 1024*1024*1;
        //分塊數(shù)量
        long chunkNum = (long) Math.ceil(length * 1.0 / chunkSize);
        //緩沖區(qū)大小
        byte[] b = new byte[1024];
        //使用RandomAccessFile訪問文件
        try {
            RandomAccessFile read = new RandomAccessFile(sourceFile, "r");
            for (int i = 0; i < chunkNum; i++) {
                //創(chuàng)建分塊文件
                File file = new File(chunkPath + i);
                //檢查文件是否存在,如果存在就刪除文件
                if(file.exists()){
                    file.delete();
                }
                //創(chuàng)建一個(gè)新文件
                boolean newFile = file.createNewFile();
                if (newFile){
                    //向分塊文件中寫數(shù)據(jù)
                    RandomAccessFile write = new RandomAccessFile(file,"rw");
                    int len = -1;
                    while ((len = read.read(b)) != -1) {
                        write.write(b, 0, len);
                        //如果分塊文件的大小大于等于分塊大小就跳過本次循環(huán)
                        if (file.length() >= chunkSize) {
                            break;
                        }
                    }
                    write.close();
                    System.out.println("完成分塊"+i);
                }

            }
            read.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

RandomAccessFile 是 Java 中的一個(gè)類,它允許對(duì)文件的任意位置進(jìn)行讀寫操作。與其他的輸入/輸出流(如 InputStream 和 OutputStream)不同,RandomAccessFile 并不屬于它們的類系,而是直接繼承自 Object 類。它提供了類似于文件系統(tǒng)中的隨機(jī)訪問功能,因此得名“隨機(jī)訪問文件”。

以下是 RandomAccessFile 的一些主要特點(diǎn)和功能:

  • 隨機(jī)訪問RandomAccessFile 允許你直接跳到文件的任意位置來讀寫數(shù)據(jù)。這是通過使用 seek(long pos) 方法實(shí)現(xiàn)的,它可以將文件的指針移動(dòng)到指定的位置。
  • 讀寫功能RandomAccessFile 既可以從文件中讀取數(shù)據(jù),也可以向文件中寫入數(shù)據(jù)。它提供了類似于 InputStream 的 read() 方法和類似于 OutputStream 的 write() 方法來執(zhí)行這些操作。
  • 文件指針操作:除了 seek(long pos) 方法外,RandomAccessFile 還提供了 getFilePointer() 方法來返回文件記錄指針的當(dāng)前位置。
  • 訪問模式:在創(chuàng)建 RandomAccessFile 對(duì)象時(shí),你需要指定一個(gè)訪問模式,它決定了文件是以只讀方式打開還是以讀寫方式打開。常見的訪問模式有 "r"(只讀)和 "rw"(讀寫)。
  • 文件操作模式:在 JDK 1.6 及更高版本中,RandomAccessFile 還支持 "rws" 和 "rwd" 模式。在 "rws" 模式下,每次寫入操作都會(huì)確保數(shù)據(jù)被寫入到磁盤中;而在 "rwd" 模式下,只有在對(duì)文件執(zhí)行了某些特定的更新操作(如關(guān)閉文件或調(diào)用 flush() 方法)后,數(shù)據(jù)才會(huì)被寫入到磁盤中。
  • 內(nèi)存映射文件:雖然 RandomAccessFile 提供了強(qiáng)大的文件訪問功能,但在某些情況下,使用 JDK 1.4 引入的“內(nèi)存映射文件”可能會(huì)更高效。內(nèi)存映射文件允許你將文件的一部分或全部映射到內(nèi)存中,從而可以像訪問內(nèi)存一樣快速地訪問文件。

文件合并 

文件合并流程:

1、找到要合并的文件并按文件合并的先后進(jìn)行排序。

2、創(chuàng)建合并文件

3、依次從合并的文件中讀取數(shù)據(jù)向合并文件寫入數(shù)

文件合并的測(cè)試代碼 :

//測(cè)試文件合并方法
    @Test
    public void testMerge(){
        try {
            //獲取源文件
            File sourceFile = new File("B:\\workspace\\test\\you.ncm");
            //分塊文件目錄
            String chunkPath="B:\\workspace\\test\\chunk\\";
            //合并后的文件
            File mergeFile = new File("B:\\workspace\\test\\you1.ncm");
            if (mergeFile.exists()) {
                mergeFile.delete();
            }
            //創(chuàng)建新的合并文件
            mergeFile.createNewFile();
            RandomAccessFile write = new RandomAccessFile(mergeFile,"rw");
            //指針指向文件頂端
            write.seek(0);
            //緩沖區(qū)
            byte[] b = new byte[1024];
            //獲取分塊文件數(shù)組
            File file = new File(chunkPath);
            File[] files = file.listFiles();
            // 轉(zhuǎn)成集合,便于排序
            List<File> fileList = Arrays.asList(files);
            //使用工具類和自定義比較類進(jìn)行排序

            Collections.sort(fileList, new Comparator<File>() {
                @Override
                public int compare(File o1, File o2) {
                    Integer o1Name = Integer.parseInt(o1.getName());
                    Integer o2Name=Integer.parseInt(o2.getName());
                    return o1Name-o2Name;
                }
            });
            //合并文件
            for (File file1 : fileList) {
                RandomAccessFile read = new RandomAccessFile(file1,"r");
                int len = -1;
                while ((len = read.read(b)) != -1) {
                    write.write(b, 0, len);

                }
                read.close();
            }
            write.close();
            //校驗(yàn)文件
            FileInputStream fileInputStream = new FileInputStream(sourceFile);
            FileInputStream mergeFileStream = new FileInputStream(mergeFile);
            //取出原始文件的md5
            String originalMd5 = DigestUtils.md5Hex(fileInputStream);
            //取出合并文件的md5進(jìn)行比較
            String mergeFileMd5 = DigestUtils.md5Hex(mergeFileStream);
            if (originalMd5.equals(mergeFileMd5)) {
                System.out.println("合并文件成功");
            } else {
                System.out.println("合并文件失敗");
            }





        } catch (Exception e) {
            e.printStackTrace();
        }


    }

視頻上傳流程 

1、前端對(duì)文件進(jìn)行分塊。

2、前端上傳分塊文件前請(qǐng)求媒資服務(wù)檢查文件是否存在,如果已經(jīng)存在則不再上傳。

3、如果分塊文件不存在則前端開始上傳

4、前端請(qǐng)求媒資服務(wù)上傳分塊。

5、媒資服務(wù)將分塊上傳至MinIO。

6、前端將分塊上傳完畢請(qǐng)求媒資服務(wù)合并分塊。

7、媒資服務(wù)判斷分塊上傳完成則請(qǐng)求MinIO合并文件。

8、合并完成校驗(yàn)合并后的文件是否完整,如果不完整則刪除文件。

測(cè)試將分塊文件上傳至minio

 //將分塊文件上傳至minio
    @Test
    public void uploadChunk(){
        String chunkFolderPath = "B:\\workspace\\test\\chunk\\";
        File chunkFolder = new File(chunkFolderPath);
        //分塊文件
        File[] files = chunkFolder.listFiles();
        //將分塊文件上傳至minio
        for (int i = 0; i < files.length; i++) {
            try {
                UploadObjectArgs uploadObjectArgs = UploadObjectArgs
                                                      .builder()
                                                      .bucket("testbucket")//桶名
                                                      .object("chunk/" + i)//存儲(chǔ)路徑+文件名
                                                      .filename(files[i].getAbsolutePath())
                                                      .build();
                minioClient.uploadObject(uploadObjectArgs);
                System.out.println("上傳分塊成功"+i);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

測(cè)試通過minio的合并文件

//合并文件,要求分塊文件最小5M
    @Test
    public void test_merge() throws Exception {
        List<ComposeSource> sources = new ArrayList<>();
        for (int i = 0; i <=7; i++) {
            ComposeSource composeSource = ComposeSource
                    .builder()//指定分塊文件信息
                    .bucket("testbucket")
                    .object("chunk/" + (Integer.toString(i)))//目標(biāo)文件信息
                    .build();
            sources.add(composeSource);
        }
        ComposeObjectArgs composeObjectArgs = ComposeObjectArgs
                                                        .builder()
                                                        .bucket("testbucket")
                                                        .object("merge01.npm")//目標(biāo)文件
                                                        .sources(sources)//源文件
                                                        .build();
        //合并文件
        minioClient.composeObject(composeObjectArgs);

    }

測(cè)試minio清除分塊文件 

//清除分塊文件
    @Test
    public void test_removeObjects(){
        //合并分塊完成將分塊文件清除
        List<DeleteObject> deleteObjects = Stream.iterate(0, i -> ++i)
                .limit(2)//循環(huán)幾次
                .map(i -> new DeleteObject("chunk/".concat(Integer.toString(i))))
                .collect(Collectors.toList());

        RemoveObjectsArgs removeObjectsArgs = RemoveObjectsArgs.builder().bucket("testbucket").objects(deleteObjects).build();
        Iterable<Result<DeleteError>> results = minioClient.removeObjects(removeObjectsArgs);
        results.forEach(r->{
            DeleteError deleteError = null;
            try {
                deleteError = r.get();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

到此這篇關(guān)于Java視頻斷點(diǎn)上傳的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Java視頻斷點(diǎn)上傳內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • java中redis增刪查以及清理緩存的案例

    java中redis增刪查以及清理緩存的案例

    這篇文章主要介紹了java中redis增刪查以及清理緩存的案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 超詳細(xì)講解Java秒殺項(xiàng)目登陸模塊的實(shí)現(xiàn)

    超詳細(xì)講解Java秒殺項(xiàng)目登陸模塊的實(shí)現(xiàn)

    這是一個(gè)主要使用java開發(fā)的秒殺系統(tǒng),項(xiàng)目比較大,所以本篇只實(shí)現(xiàn)了登陸模塊,代碼非常詳盡,感興趣的朋友快來看看
    2022-03-03
  • 詳解Java中“==”與equals()的區(qū)別

    詳解Java中“==”與equals()的區(qū)別

    這篇文章主要介紹了詳解Java中“==”與equals()的區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • 如何把Java程序窗口在屏幕中間顯示

    如何把Java程序窗口在屏幕中間顯示

    大家在日常Java開發(fā)中,可能會(huì)需要把程序窗口定位在屏幕中間,那該如何操作呢,下面來一起看看。
    2016-08-08
  • springboot 項(xiàng)目使用jasypt加密數(shù)據(jù)源的方法

    springboot 項(xiàng)目使用jasypt加密數(shù)據(jù)源的方法

    Jasypt 是一個(gè) Java 庫(kù),它允許開發(fā)者以最小的努力為他/她的項(xiàng)目添加基本的加密功能,而且不需要對(duì)密碼學(xué)的工作原理有深刻的了解。接下來通過本文給大家介紹springboot 項(xiàng)目使用jasypt加密數(shù)據(jù)源的問題,一起看看吧
    2021-11-11
  • 使用maven項(xiàng)目pom.xml文件配置打包功能和靜態(tài)資源文件自帶版本號(hào)功能

    使用maven項(xiàng)目pom.xml文件配置打包功能和靜態(tài)資源文件自帶版本號(hào)功能

    在Maven項(xiàng)目中,通過pom.xml文件配置打包功能,可以控制構(gòu)建過程,生成可部署的包,同時(shí),為了緩存控制與版本更新,可以在打包時(shí)給靜態(tài)資源文件如JS、CSS添加版本號(hào),這通常通過插件如maven-resources-plugin實(shí)現(xiàn)
    2024-09-09
  • Jmeter設(shè)置全局變量token過程圖解

    Jmeter設(shè)置全局變量token過程圖解

    這篇文章主要介紹了Jmeter設(shè)置全局變量token過程圖解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • 使用json字符串插入節(jié)點(diǎn)或者覆蓋節(jié)點(diǎn)

    使用json字符串插入節(jié)點(diǎn)或者覆蓋節(jié)點(diǎn)

    這篇文章主要介紹了使用json字符串插入節(jié)點(diǎn)或者覆蓋節(jié)點(diǎn)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java中的跨域和@CrossOrigin注解的作用詳解

    Java中的跨域和@CrossOrigin注解的作用詳解

    這篇文章主要介紹了Java中的跨域和@CrossOrigin注解的作用詳解,跨域,指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對(duì)JavaScript施加的安全限制,需要的朋友可以參考下
    2023-12-12
  • SpringBoot XSS攻擊的常見形式與防范方法

    SpringBoot XSS攻擊的常見形式與防范方法

    XSS攻擊是指攻擊者在Web頁(yè)面的輸入數(shù)據(jù)中插入惡意腳本,當(dāng)其他用戶瀏覽該頁(yè)面時(shí),這些腳本就會(huì)在用戶的瀏覽器上執(zhí)行,可能導(dǎo)致信息泄露、會(huì)話劫持、惡意操作等安全風(fēng)險(xiǎn),本文給大家介紹了SpringBoot XSS攻擊的常見形式與防范方法,需要的朋友可以參考下
    2024-11-11

最新評(píng)論