如何调用CMD实现多个同类文件合并的研究 二进制 依次 文本图像视频音频

笔记哥 / 03-14 / 0点赞 / 0评论 / 551阅读
# 引言 视频网站内,使用视频下载嗅探器下载了视频,打开资源管理器一看,是几千个.ts文件,见下图: ![](https://cdn.res.knowhub.vip/c/2504/03/bac92974.png?G1QAAOTcVkxwP3K2iOF0Q2CDZkCiiqBSz3q956x9A3x%2fMLLmZ7Q%2bY3%2f4Q%2bszwFVNDRjZUJA8MSlWrpeW5Igi5mR5jQA%3d)  ![](https://cdn.res.knowhub.vip/c/2504/03/6658d937.png?G1UAAETn9LwUqODCvtMdbIlTE20GKtIIKvWs13vO2jfR9wcYmp%2fR%2boz94RetzyBXNTUCw7ggBYEoO5sXT6IoFcJXzWsE) 通过播放部分视频,发现其实内容是完整的,只是自动切割了多份,倘若无缝拼接为一个完整视频单元,就可以正常播放观赏了。 经过考虑, - 可以使用视频编辑软件,比如PR,导入素材然后重新编排输出,缺点是耗时,而且二次编码损画面质量; - 可以考虑使用无损拼接视频的工具,可参考笔者另一篇博文:[【视频分割工具】无损快速分割视频软件分享\[切分\]\[分P神器\]](https://www.bilibili.com/opus/561236128335705734?spm_id_from=333.1387.0.0 "【视频分割工具】无损快速分割视频软件分享[切分][分P神器]") - 或者直接使用命令提示符 / 终端,调用**FFmpeg**等工具。或者不借助任何工具或插件,就用原生的MS-Dos。 相信原生dos可以实现。那么如果素材是文本、图像和音频呢,我们一同尝试一下。 * * * # 首先 简单尝试copy命令: ```powershell copy /b 1.ts+2.ts+3.ts combine.ts ```  可以得到理想结果,三个片段结合至一个且正常播放。`copy`命令是cmd中常用的操作文件指令,它可以进行拷贝文件、修改命名、移动文件等,这里使用了合并文件的功能,使用操作符**`+`**。`/b`代表二进制式操作。 如果暴力得写下命令如: ```powershell copy /b 0.ts+1.ts+2.ts+...+2368.ts combine.ts ``` 咱们是可以理解的,但是dos理解不了。需要详细定义什么是**“...”** 因此需要把所有的文件清单列出来,即每个文件的文件名加后缀的清单,每个文件名间加“+”。如: ![](https://cdn.res.knowhub.vip/c/2504/03/15ebb674.png?G1UAAETn9LwUoGB03%2bkOtsSpiWsGKtIIKvWs1%2fP%2f%2b1xE7xfKavmefaw4H37RxwpqZm5OyuoMpCBghkNKKUlQq6M1Qd4zAA%3d%3d) 新建一个批处理程序.**bat**,使用`for`循环,把字符整理好一并存入一变量里,如下脚本: ```powershell set "fileList=" REM 变量 用于存放字符 for /L %%i in (0, 1, 2368) do ( set "fileList=!fileList!%%i.ts+" REM 依次拼接字符 ) set "fileList=!fileList:~0,-1!" REM 移除最后一个 + ``` 执行后发现,只有连接到1160.ts。后面的并没有执行: ![](https://cdn.res.knowhub.vip/c/2504/03/4ffa03ed.png?G1UAAMTsdJxI8kmobqMO2jvFHc1ARRpBpZ71es9Z%2byb6%2fgaGxWfUPtv%2b8IvaZ6Ni5uYEhrMiBIG4KyRfCAJOWXMqGtdo) 什么原因呢,最可疑的是变量的缓冲容量限制,存不下那么多字符。最直接的解决方法是可以**分批次**进行处理: 1. 第一批次  0.ts+1.ts+2.ts+...+999.ts ,合并为combine1.ts 2. 第二批次  1000.ts+1001.ts+1002.ts+...+1999.ts ,合并为combine2.ts 3. 第三批次  2000.ts+2001.ts+2002.ts+...+2348.ts ,合并为combine3.ts 4. 最后  combine1.ts+combine2.ts+combine3.ts ,  合并为combine.ts ```powershell REM @echo off setlocal enabledelayedexpansion ::--------第一批次--------------- set "outputFile=combine1.ts" set "fileList=" for /L %%i in (0, 1, 999) do ( set "fileList=!fileList!%%i.ts+" ) set "fileList=!fileList:~0,-1!" REM 移除最后一个+ echo !fileList! > ./fileList.txt REM 方便调试 copy /b !fileList! "%outputFile%" ::----------------------------- pause ::--------第二批次--------------- set "outputFile=combine2.ts" set "fileList=" for /L %%i in (1000, 1, 1999) do ( set "fileList=!fileList!%%i.ts+" ) set "fileList=!fileList:~0,-1!" REM 移除最后一个+ echo !fileList! > ./fileList.txt copy /b !fileList! "%outputFile%" ::----------------------------- pause ::--------第三批次--------------- set "outputFile=combine3.ts" set "fileList=" for /L %%i in (1999, 1, 2348) do ( set "fileList=!fileList!%%i.ts+" ) set "fileList=!fileList:~0,-1!" REM 移除最后一个+ echo !fileList! > ./fileList.txt copy /b !fileList! "%outputFile%" ::----------------------------- pause ::--------最后----------------- copy /b combine1.ts+combine2.ts+combine3.ts combine.ts pause ``` 放在 .ts 文件所在文件夹下,运行脚本,得到最后的视频文件combine.ts。经测验,正常播放,没有问题! * * * # 接着 有同学可能要提议,说cmd中最有魅力的莫过于通配符的使用,例如可以使用 **\*.ts** 代指文件夹下所有的ts文件,那么可以这样做**【注意,以下是错误结果】:** ```powershell copy /b *.ts combine.ts ``` 可是经测试,这样操作是可行,但是结果不理想,把所有的文件合并为一个,但是打开之后发现视频全部打乱,无法正常欣赏。因此暴力式合并是不可取的。 如果想要更随心得管理命令,应该将有待合并的文件名导出成数个数据文件,比如.**txt**,然后读取这些文件的文本,作为`copy`命令的参数,随后执行! **PS: 不过如果遇到其他格式的视频文件,用 copy /b 命令,大概率是无法合成正常播放的文件的,因为不同格式,有不同的编码设计,直接拼接是无可取的。(感谢网友[firstrose](https://www.cnblogs.com/firstrose "firstrose")的教导)** 对了,笔者在***引言***中说到,对于其他格式的文件也想试试合并操作,那么下面给出几个**示例**: * * * ## 文本合并 设有四个**txt**文档,有序合并为一个: ```powershell copy /a 1.txt+2.txt+3.txt+4.txt final.txt ``` 或者逐一把每一个文档先读出来放变量中,然后合并: 四个文档对应四个字符串变量   var1  var2   var3   var4   , 最后字符合并,输出给新变量,然后**echo >** 重定向给.txt保存下来。见代码: ```powershell @echo off setlocal enabledelayedexpansion rem 定义要读取的四个文件 set "file1=1.txt" set "file2=2.txt" set "file3=3.txt" set "file4=4.txt" rem 定义合并后的文件 set "mergedFile=merged.txt" rem 读取第一个文件内容到变量 var1 set "var1=" for /f "usebackq delims=" %%a in ("%file1%") do ( set "var1=!var1!%%a" set "var1=!var1!" ) rem 读取第二个文件内容到变量 var2 set "var2=" for /f "usebackq delims=" %%a in ("%file2%") do ( set "var2=!var2!%%a" set "var2=!var2!" ) rem 读取第三个文件内容到变量 var3 set "var3=" for /f "usebackq delims=" %%a in ("%file3%") do ( set "var3=!var3!%%a" set "var3=!var3!" ) rem 读取第四个文件内容到变量 var4 set "var4=" for /f "usebackq delims=" %%a in ("%file4%") do ( set "var4=!var4!%%a" set "var4=!var4!" ) rem 合并四个变量的内容 set "mergedContent=!var1!!var2!!var3!!var4!" rem 将合并后的内容写入新文件 echo !mergedContent! > "%mergedFile%" echo 文件合并完成,合并后的文件为 %mergedFile% endlocal ``` 不过这番操作,仅仅是字符操作,并没有换行,因此合成了一行。另外还有`type`命令也可以实现类似操作。 * * * ## 图像合并 对于图像操作,纯粹靠dos原生系统是几乎不可能的,图像操作需要很复杂的运算,需要其他工具。 可以尝试使用**PowerShell**,调用程序集,如 **System.Drawing**。 ```powershell # 添加 System.Drawing 程序集以便使用图像处理类 Add-Type -AssemblyName System.Drawing # 从文件加载第一张图片 $img1 = [System.Drawing.Image]::FromFile("image1.jpg") # 从文件加载第二张图片 $img2 = [System.Drawing.Image]::FromFile("image2.jpg") # 计算新图像的宽度:两张图片的宽度之和 $width = $img1.Width + $img2.Width # 计算新图像的高度:取两张图片中较高的高度 $height = [Math]::Max($img1.Height, $img2.Height) # 创建一个新的位图对象,用于存储合并后的图片 $newImage = New-Object System.Drawing.Bitmap $width, $height # 从新创建的位图中获取图形对象,以便进行绘制 $graphics = [System.Drawing.Graphics]::FromImage($newImage) # 在新图像的 (0, 0) 位置绘制第一张图片 $graphics.DrawImage($img1, 0, 0) # 在新图像的 (img1.Width, 0) 位置绘制第二张图片,确保它紧挨着第一张 $graphics.DrawImage($img2, $img1.Width, 0) # 将合并后的图像保存为一个新的 JPG 文件 $newImage.Save("merged_image.jpg") # 释放图形对象和图像对象的资源 $graphics.Dispose() $img1.Dispose() $img2.Dispose() $newImage.Dispose() # 输出合并完成的提示 Write-Host "合并完成,输出文件为: merged_image.jpg" ```  这样两张图片便可简单的“粘合在一起”。还有其他细节可以参考笔者另一篇文章:[PowerShell开发小工具 · 四张照片拼成一张](https://www.cnblogs.com/sharpeye/p/18744376 "PowerShell开发小工具 · 四张照片拼成一张 ") 如果执意要用dos,可以找图像处理库,比如 **ImageMagicK**。下面是合并2张图片的示例代码: ```powershell @echo off rem 配置图片地址以及名称,还有要合并的图片文件名 set img1=1.jpg set img2=2.jpg set output=merged_image.jpg rem 检查 ImageMagick 是否安装 where magick >nul 2>nul if errorlevel 1 ( echo ImageMagick 未安装,请先安装 ImageMagick。 exit /b ) rem 合并图片,使用 +append 水平合并 magick "%img1%" "%img2%" +append "%output%" echo 合并完成,输出文件为: %output% pause ``` **PS**: 在安装过程中,确保选中“Install legacy utilities (e.g., convert)”选项,以便使用命令行工具。 以下给一个5张照片水平拼接的例子: ![](https://cdn.res.knowhub.vip/c/2504/03/0d8e3072.jpg?G1UAAER17rxgo%2btI8DvxmBoUEmwGKtIIKvWs1%2fX%2fax8i9xtQMJ9fHzP2h1%2f0MUMa6XSBwtWQQgEMRK1NU3EaGwzIzwo%3d)  ![](https://cdn.res.knowhub.vip/c/2504/03/604e3278.jpg?G1UAAMTW3Dgp8IJm22gD1Vl6p81ARRpBpZ71uvee6yR6PgdD4%2fW3Pnx9%2bEXrw6mqmhqBYZwQggAJBQKuQQ5wyqUa4jsd)  ![](https://cdn.res.knowhub.vip/c/2504/03/615f12bd.jpg?G1QAAMTW3Dgp%2bEBF22gD1Vl6p82ARBVBpZ71utca8yR6vgBD8%2fXX1mN%2b%2bENtPchVTY3AMBYkXwCBqu%2bQVDZzsMuR3xE%3d)  ![](https://cdn.res.knowhub.vip/c/2504/03/4c37b19c.jpg?G1UAAER17rxgo3QS%2fE48pgaFBJqBijSCSj3rde891ynyfA4F4%2fW3Pnx9%2bEXrw6WSRhMoTDNCSECGJQVrSOUgWYAc3%2bk%3d)  ![](https://cdn.res.knowhub.vip/c/2504/03/db0f197c.jpg?G1QAAMTW3Dgp8MIZbaMNVGfpnTYDElUElXrW6957rpPo%2bQIMzdff%2boj14Q%2btjyBXNTUCw7ggeQEKTNwZqerBLFo8vzMA) 上面5张图片,水平合并: ```powershell magick 1.jpg 2.jpg 3.jpg 4.jpg 5.jpg +append combine_5.jpg ``` 得: ![](https://cdn.res.knowhub.vip/c/2504/03/cfdcaeeb.jpg?G1QAAER17rxgo3QB%2fU48pgaFBJoBiSqCSj3rde891ynyfA4F4%2fW3Pnx9%2bEPrw%2bUgjSZQmGYEn4CcYVYUgZWoWhLiOx0%3d) 照片大小都不一致,因此会得到很奇怪的效果。 * * * ## 音频合并 最后还有音频文件的合并尝试。准备3段音频:1.wav   2.wav  3.wav  (不同格式的还是不要自找苦吃了,先转换格式吧) 对于音频文件,cmd不好处理的,还是用**FFmpeg**吧!不过千万别以为笔者没试过,强制执行`copy /b`,要么打不开,要么音频播放软件识别错误,即使能播放,时间线也是**错乱**的! 下面是使用**FFmpeg**工具集的例子: ```powershell rem @echo off rem 设置要合并的 WAV 文件名 set wav1=1.wav set wav2=2.wav set wav3=3.wav set output=merged_output.wav rem 检查 FFmpeg 是否安装 where ffmpeg >nul 2>nul if errorlevel 1 ( echo FFmpeg 未安装,请先安装 FFmpeg。 pause exit /b ) rem 创建一个临时文件,列出要合并的 WAV 文件 ( echo file '%wav1%' echo file '%wav2%' echo file '%wav3%' ) > file_list.txt rem 使用 FFmpeg 合并 WAV 文件 ffmpeg -f concat -safe 0 -i file_list.txt -c copy "%output%" rem 删除临时文件 del file_list.txt echo 合并完成,输出文件为: %output% pause ``` **PS:** 使用 `ffmpeg` 命令进行合并。选项 `-f concat` 指定格式为拼接,`-safe 0` 允许使用绝对路径,`-c copy` 表示直接复制音频流。 * * * # 结尾 合并文件,如果不是像笔者闲得蛋疼,还是别去使用cmd做,交给专业软件或工具吧。此篇文章也就是试验一下,不过针对学习cmd命令行脚本而言是很有参考价值。 而对于文本而言,其实cmd来合并操作,有时候还有用武之地,以后碰到了再细聊。视频的话,遇到像本文一开始的情景,很多同格式同规格的视频文件,使用copy /b 还挺方便的。