通过C++程序实现光驱的自动化刻录和读取

文章目录

    • ISO文件格式
    • 光盘的基本概念
    • 光盘种类特点
    • DVD+R光盘使用
    • windows调用
    • Linux调用
      • Linux平台下用到的C++库:
      • 读取设备驱动列表
      • 向光驱中写文件

数字存储媒体快速发展的今天,光驱的使用已经不像以前那样普及了。但是在数据备份、安装软件和操作系统、旧设备兼容等领域还有在使用。

ISO文件格式

在刻录普通文件到光盘时,并不一定需要将它们制作成ISO文件。你可以使用光盘刻录软件直接添加文件到光盘中,而无需事先制作ISO文件。而如果你希望确保光盘上的文件与多个操作系统兼容或者需要创建一个可引导的光盘,那么制作成ISO文件可能是一个更好的选择。在这种情况下,你可以在刻录软件中选择制作ISO映像,然后再将该ISO文件刻录到光盘上。

制作成ISO文件的优点:
1.保持文件的完整性和一直性 2.兼容多个操作系统 3.可以跨平台使用 4.方便管理和存储

光盘的基本概念

Session(会话): 会话是光盘上的一个逻辑刻录单元。每次进行刻录,都会创建一个新的会话。
Track(轨道): 轨道是光盘上的一个圆形路径,沿着这个路径数据被刻录和读取。光盘上通常有许多并行的轨道,每个轨道都划分为一系列的扇区。
Sector(扇区): 扇区是光盘上最小的物理存储单元,是数据的基本单元。一个光盘被划分为许多扇区,每个扇区通常包含2048字节(2KB)的数据。

光盘种类特点

根据光盘的写入类型、用途、容量,光盘分为很多种类,详细分类如下:

CD(Compact Dis) 典型容量为700MB
1.CD-ROM(Read-Only Memory): 只读光盘 用于分发软件、应用和视频
2.CD-R(Recordable): 可以一次性写入, 写入之后不能修改,常用于备份音乐和数据
3.CD-RW(ReWritable): 可多次擦写和重写,适合频繁修改数据

DVD(Digital Versaatile Disc) 单层容量为4.7GB 双层容量为8.5GB
1.DVD-ROM: 类似于CD-ROM,只读光盘,用于电影、软件等的分发。
2.DVD-R: 一次写入型,用于备份和分发。
3.DVD+R: 一次写入型,与DVD-R相似。
4.DVD-RW: 可多次擦写和重写。
5.DVD+RW: 与DVD-RW类似。

Blu-ray Disc(BD) 单层容量为25GB 双层容量为50GB
1.BD-ROM: 用于高清电影和软件分发的一次写入型。
2.BD-R: 一次写入型,用于高容量数据备份。
BD-RE(Rewritable): 可多次擦写和重写,适用于频繁修改的数据。

HD DVD(已基本淘汰)
HD DVD-ROM: 用于高清电影和软件分发的一次写入型。
HD DVD-R: 一次写入型,用于备份和分发。
HD DVD-RW: 可多次擦写和重写。

Mini光盘
Mini CD 和 Mini DVD: 较小尺寸的光盘,用于特定设备和应用。

DVD+R光盘使用

这里以DVD+R光盘为例说明一下,光盘的使用和初始化,初始化界面如下:

在这里插入图片描述
1.初始化为U盘模式之后我们就可以使用光盘反复读写文件了,但每次读写都会消耗有限的磁盘读写空间。
2.初始化为用于CD/DVD播放机模式的时候,就只可以写入一次了,再次写入会将磁盘损坏。

DVD+R采用了一种称为Incremental Sequential Recording(增量顺序写入)写入方式,该方式不允许在会话关闭后继续写入。在DVD+R上创建一个会话后,一旦会话被关闭(Finalized),就不能再向该会话中追加写入新的数据。

windows调用

Windows操作光驱需要使用IMAPI(Image Mastering API)
IMAPI是一个用于创建和写入光盘映像文件的Windows API。它可以用于将文件和文件夹内容写入光盘,并创建可引导光盘。

1.创建映像对象

// 初始化 COM
CoInitializeEx(NULL, COINIT_MULTITHREADED); 

IDiscMaster* pDiscMaster = NULL;
HRESULT hr = CoCreateInstance(__uuidof(MsftDiscMaster2), NULL, CLSCTX_INPROC_SERVER, __uuidof(IDiscMaster2), (void**)&pDiscMaster);  

if (SUCCEEDED(hr)) {
    // 成功创建 
} else {
    // 创建失败
}

2.获取光驱数量和ID

IDiscMaster* pDiscMaster = NULL;
long totalDevices = 0; //光驱数量
HRESULT hr = CoCreateInstance(__uuidof(MsftDiscMaster2), NULL, CLSCTX_INPROC_SERVER, __uuidof(IDiscMaster2), (void**)&pDiscMaster);  
hr = m_discMaster->get_Count(&totalDevices);   
BSTR	uniqueID = NULL;  //光驱的ID
hr = m_discMaster->get_Item(0, &uniqueID);  

3.初始化刻录类

IDiscRecorder2* discRecorder = NULL;
BSTR recordUniqueId;
SAFEARRAY* m_volumePathNames;
HRESULT hr = CoCreateInstance(__uuidof(MsftDiscRecorder2), NULL, CLSCTX_INPROC_SERVER, __uuidof(IDiscRecorder2), (void**)&discRecorder);  
if (FAILED(hr)) return false;

//初始化刻录类
discRecorder->InitializeDiscRecorder(recordUniqueId);

//获取卷    
discRecorder->get_VolumePathNames(&m_volumePathNames);  

参考项目

Linux调用

Linux平台下用到的C++库:

1.libburn
libburn 是一个用于写入光盘的库,它支持 CD、DVD 和 Blu-ray。它提供了 C 接口,可以在 C++ 中使用。libburn 允许你创建数据和音频光盘,并提供了对光驱的低级别访问。
https://dev.lovelyhq.com/libburnia/libburn

sudo apt-get install libburn-dev

2.libcdio
libcdio 提供了一种接口,用于访问 CD-ROM 和 DVD-ROM 设备。它包括一组 C 函数,允许你读取光盘的数据、音轨等信息。libcdio 还包含用于访问 ISO-9660 文件系统的功能。
https://www.gnu.org/software/libcdio/

sudo apt-get install libcdio-dev  

3.libudev
libudev 是一个用于管理设备的库,你可以使用它来检测和获取有关设备的信息,包括 USB 光驱。你可以通过监听 udev 事件来获取插拔 USB 设备的通知。

sudo apt-get update  
sudo apt-get install libudev-dev  

读取设备驱动列表

1.使用libburn库读设备列表
使用libburn库读取USB光驱设备时异常,无法读取USB光驱。

参考项目

#include <iostream>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "libburn/libburn.h"

using namespace burn;
using namespace std;

int main(int argc, char const *argv[])
{
    struct burn_drive_info *drive_list;
    unsigned int drive_count = 0;
    int ret;
    //初始化libburn 
    if (!burn_initialize()){
	    cout << "init libburn failed" << endl;
	}
  
    //获取光驱的数量
    while(!burn_drive_scan(&drive_list, &drive_count));
        usleep(100002);

    if(drive_count <=0)
    {
        cout << "error to scan drive" << endl;
        return -1;
    }
    
    //抓取光驱
    ret = burn_drive_grab(drive_list[0].drive, 1);
    if(!ret)
    {
        cout << "error to grab the drive";
        return -1;
    }

    //释放光驱
    burn_drive_release(drive_list[0].drive, 1);
    //结束
    burn_finish();
    return 0;
}

2.使用liudev获取设备列表

#include <iostream>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <libudev.h>
#include <linux/cdrom.h>
#include <fcntl.h>
#include <sys/ioctl.h>
/**
 * 获取所有光驱的列表
 */
std::vector<std::string> GetOpticalDriveList()
{
	udev* udev_context = udev_new();
	if (!udev_context)
		return {};

	std::vector<std::string> drives;
	udev_enumerate* enumerate = udev_enumerate_new(udev_context);
	if (enumerate)
	{
		udev_enumerate_add_match_subsystem(enumerate, "block");
		udev_enumerate_add_match_property(enumerate, "ID_CDROM_DVD", "1");
		udev_enumerate_scan_devices(enumerate);
		udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);

		udev_list_entry* dev_list_entry;
		udev_list_entry_foreach(dev_list_entry, devices)
		{
			const char* path = udev_list_entry_get_name(dev_list_entry);
			udev_device* device = udev_device_new_from_syspath(udev_context, path);
			const char* devnode = udev_device_get_devnode(device);
			if (devnode)
				drives.push_back(devnode);
			udev_device_unref(device);
		}
		udev_enumerate_unref(enumerate);
	}
	udev_unref(udev_context);

	return drives;
}

/**
 * 检查光驱是否可用
 */
bool GetValidDrive(std::string& drive)
{
	if (!drive.empty())
	{
		int fd = open(drive.c_str(), O_RDONLY | O_NONBLOCK);
		if (fd != -1)
		{
			if (ioctl(fd, CDROM_GET_CAPABILITY, 0) == -1){
               close(fd);
               return false;     
            }
			close(fd);
            return true;
		}
		else
		{
            return false;
		}
	}else{
        return false;
    }
}

3.使用libcdio库获取光驱数量

#include <cdio/cdio.h>
#include <cdio/cd_types.h>
#include <cdio/logging.h>

//打印日志
static void  log_handler(cdio_log_level_t level, const char message[])
{
  switch(level) {
  case CDIO_LOG_DEBUG:
  case CDIO_LOG_INFO:
    return;
  default:
    printf("cdio %d message: %s\n", level, message);
  }
}

int main(int argc, const char *argv[])
{
  char **ppsz_cd_drives=NULL, **c;
  
  //设置日志的回调函数
  cdio_log_set_handler(log_handler);

  //打印设备的CD驱动
  ppsz_cd_drives = cdio_get_devices(DRIVER_DEVICE);
  if (NULL != ppsz_cd_drives) 
    for( c = ppsz_cd_drives; *c != NULL; c++ ) {
      printf("-- Drive:  %s\n", *c);
    }

  //释放CD驱动
  cdio_free_device_list(ppsz_cd_drives);
  ppsz_cd_drives = NULL;
  printf("-----\n");
  return 0;
}

向光驱中写文件

通过命令行向光驱中写文件

# -Z 向选中的设备中烧入一个初始的session  
# -M 添加一个新的Session, 选项来避免关闭会话,从而在后续操作中保持会话打开
# -dvd-compat 提供对DVD-ROM的最大兼容性  
# -speed=N 指定光驱的刻录速度  
# -R: 用于支持 UNIX 文件系统的长文件名和权限
# -J: 用于支持 Windows 文件系统的长文件名。

# 初始化写入
growisofs -Z /dev/sr1 -R -J /home/users/file1 /home/users/file2  
# 追加写入  
growisofs -M /dev/sr1 -R -J /home/users/file3  

通过libburn命令写入文件

#include <iostream>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "libburn/libburn.h"

using namespace burn;
using namespace std;

void burn_iso_to_disc(struct burn_drive *drive, char *iso_path)
{
    struct burn_source *data_src = NULL, *fifo_src = NULL;
    struct burn_disc *target_disc = NULL;
    struct burn_session *session = NULL;
    struct burn_write_opts *burn_options = NULL;
    enum burn_disc_status disc_state;
    struct burn_track *track;
    struct burn_progress progress;
    int fd = 0;
    off_t fixed_size;
    int fifo_chunksize = 2048;
    int fifo_chunks = 2048;
    int padding = 300 * 1024; //a padding of 300 kiB helps to avoid the read-ahead bug
    char reasons[BURN_REASONS_LEN];
    struct stat stbuf;
    time_t start_time;

    target_disc = burn_disc_create();
    session = burn_session_create();
    burn_disc_add_session(target_disc, session, BURN_POS_END);

    track = burn_track_create();
    burn_track_define_data(track, 0, padding, 1, BURN_MODE1);

    //打开需要写入的数据
    fd = open(iso_path, O_RDONLY);
    if (fd >= 0)
        if (fstat(fd, &stbuf) != -1)
            if ((stbuf.st_mode & S_IFMT) == S_IFREG)
                fixed_size = stbuf.st_size;
            else
            {
                cout << "error to open  filedescriptor\n"
                     << endl;
                return;
            }

    //转换文件为可写入的文件对象
    data_src = burn_fd_source_new(fd, -1, fixed_size);
    if (data_src == NULL)
    {
        cout << "Could not open data source " << iso_path << endl;
        return;
    }

    //安装fifo对象到数据源对象中
    fifo_src = burn_fifo_source_new(data_src, fifo_chunksize, fifo_chunks, 0);
    if (fifo_src == NULL)
    {
        cout << "Could not create fifo object of 4 MB\n"
             << iso_path << endl;
        return;
    }
    if (burn_track_set_source(track, fifo_src) != BURN_SOURCE_OK)
    {
        cout << "Cannot attach source object to track object\n";
        return;
    }

    burn_session_add_track(session, track, BURN_POS_END);

    burn_source_free(data_src);

    //检测驱动的状态
    disc_state = burn_disc_get_status(drive);
    if (disc_state != BURN_DISC_BLANK && disc_state != BURN_DISC_APPENDABLE)
    {
        return;
    }

    //创建烧写配置
    burn_options = burn_write_opts_new(drive);
    burn_write_opts_set_perform_opc(burn_options, 0); 
    burn_write_opts_set_multi(burn_options, 0);
    burn_write_opts_set_simulate(burn_options, 0);
    burn_write_opts_set_underrun_proof(burn_options, 1);
    if (burn_write_opts_auto_write_type(burn_options, target_disc, reasons, 0) == BURN_WRITE_NONE)
    {
        cout << "FATAL: Failed to find a suitable write mode with this media.\n"
             << "Reasons given:" << endl
             << reasons << endl;
        return;
    }
    burn_drive_set_speed(drive, 0, 0);

    burn_set_signal_handling((void*)"libburner : ", NULL, 0x30);

    cout << "Burning starts. With e.g. 4x media expect up to a minute of zero progress.\n";
   
    burn_disc_write(burn_options, target_disc);

    while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
		usleep(100002);
    while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE)
    {
        int size, free_bytes, ret;
        char *status_text;

        ret = burn_fifo_inquire_status(fifo_src, &size, &free_bytes, &status_text);
        if(ret > 0)
            cout << "fifo " << status_text << " %% " << 100 - (100.0*free_bytes/size) << " fill" << endl;

        sleep(1);
    }

    //释放缓存
    burn_write_opts_free(burn_options);
    burn_source_free(fifo_src);
    burn_track_free(track);
    burn_disc_free(target_disc);
}

int main(int argc, char const *argv[])
{
    struct burn_drive_info *drive_list;
    unsigned int drive_count = 0;
    int ret;

    //初始化
    if (!burn_initialize()){
        cout << "init burn drive failed" << endl;
		return -1;
	}

    //检测光驱
    while(!burn_drive_scan(&drive_list, &drive_count));
        usleep(100002);
    if(drive_count <=0)
    {
        cout << "error to scan drive" << endl;
        return -1;
    }

    //捕获光驱
    ret = burn_drive_grab(drive_list[0].drive, 1);
    if(!ret)
    {
        cout << "error to grab the drive";
        return -1;
    }

    //写文件
    burn_iso_to_disc(drive_list[0].drive, "myiso.iso");

    //释放光驱
    burn_drive_release(drive_list[0].drive, 1);
    burn_finish();
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/276334.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LTPI协议的理解——LTPI协议的定义和结构

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 LTPI协议的理解——LTPI协议的定义和结构 定义DC-SCM 2.0 LTPI 结构GPIO通道I2C/SMBus通道Uart通道OEM通道数据通道 总结 定义 LTPI (LVDS Tunneling Protocol & Interf…

算法基础之计数问题

计数问题 核心思想&#xff1a; 数位dp / 累加 累加 ​ 分情况讨论 &#xff1a; xxx 000 ~ abc –1 yyy 000 ~ 999 共 abc * 1000 种 特别地&#xff0c;当枚举数字0时 (找第4位为0的数) 前三位不能从000开始了 否则没这个数不合法(有前导零) xxx abc 2.1. d < 1 , 不…

拥抱健康,远离内耗:程序员必备的情绪管理策略

程序员是一群特别脆弱的群体&#xff0c;俗称IT民工&#xff01; 每天上班要跟产品斗智斗勇&#xff0c;还要跟bug斗的难解难分&#xff0c;另外还要被领导批&#xff0c;跟同事扯皮&#xff0c;整个一天下来常常筋疲力尽。 程序员大多不善言语&#xff0c;受了委屈往往喜欢吞到…

抓包工具Charles安装及使用

Charles 介绍 Charles 是在 Mac 下常用的网络封包截取工具&#xff0c;在做 移动开发时&#xff0c;我们为了调试与服务器端的网络通讯协议&#xff0c;常常需要截取网络封包来分析。 Charles 通过将自己设置成系统的网络访问代理服务器&#xff0c;使得所有的网络访问请求都…

GameFi 2024年或将迎来新的爆发!

在数字时代&#xff0c;游戏已经不仅仅是一种娱乐方式&#xff0c;更是一种跨越现实和虚拟界限的全球性文化现象。而游戏金融&#xff08;GameFi&#xff09;正是这场数字革命的下一个巨大风潮。 随着科技的不断发展和创新&#xff0c;2024年&#xff0c;GAMEFI&#xff08;Gam…

购买腾讯云服务器需要多少钱?购买腾讯云服务器方法教程

腾讯云轻量应用服务器购买指南&#xff0c;有两个入口&#xff0c;一个是在特价活动上购买&#xff0c;一个是在轻量应用服务器官方页面购买&#xff0c;特价活动上购买价格更便宜&#xff0c;轻量2核2G3M带宽服务器62元一年起&#xff0c;阿腾云atengyun.com分享腾讯云轻量应用…

【最新报道】初窥Windows AI 工作室

自我介绍 做一个简单介绍&#xff0c;酒研年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【…

Python+OpenCV 零基础学习笔记(6):ROI

文章目录 相关链接运行环境前言ROI颜色区域分割颜色通道合并 相关链接 【2022B站最好的OpenCV课程推荐】OpenCV从入门到实战 全套课程 CSDN标题里个括号对应视频的分P OpenCVPython CSDN专栏 Gitee 项目地址 运行环境 Python:3.11.5Anaconda:23.7.4IDE:vscode运行环境&#x…

three.js 模型 居中

物体不居中 模型的几何中心位置不对&#xff0c; 设置偏离物体实际几何中心&#xff0c;当设置position&#xff08;0,0,0&#xff09;时就会出现偏离。 解决方案 此处有两种解决方案 建模师处理模型&#xff0c;将模型的几何中心移动到&#xff08;0&#xff0c; 0&#…

数据集介绍【02】CIFAR10

CIFAR10数据集共有60000个样本&#xff0c;每个样本都是一张32*32像素的RGB图像&#xff08;彩色图像&#xff09;&#xff0c;每个RGB图像又必定分为3个通道&#xff08;R通道、G通道、B通道&#xff09;。这60000个样本被分成了50000个训练样本和10000个测试样本。 CIFAR10数…

使用terraform 来创建GCP的instance template 和基于它的vm

本人在上一篇的文章中已经介绍了如何去创建 google cloud的 vm 的image 和 instance template了 url&#xff1a; 快速构建自定义配置好的VM - 使用GCP instance-template 和 custom-image 但是里面的操作是基于gcloud CLI的。 在实际项目上&#xff0c; 我们对google cloud …

Mysql For Navicate (老韩)

Navicate创建数据库 先创建一个数据库;然后在数据库中创建一张表;在表格当中填入相应的属性字段;打开表, 然后填入相应的实例字段; – 使用数据库图形化App和使用指令来进行操作各有各的好处和利弊; 数据库的三层结构(破除MySQL神秘) 所谓安装Mysql数据库, 就是在主机安装一…

树莓派界面改成中文

安装完树莓派系统(Raspberry Pi OS with Desktop)&#xff0c;第一次启动时&#xff0c;时会有如下面二个图所示&#xff0c;让你选择区域时区和语言。 树莓派默认的语言为英文&#xff0c;如果你在安装时没有选择的话&#xff0c;默认的区域为英国&#xff0c;语言为英国英文&…

java数据结构与算法刷题-----LeetCode 680. 验证回文串 II

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 思路&#xff1a;双指针 详情见代码注释 class Solution {//贪心双指针&a…

apisix 插件配置 未生效 未起作用

插件配置完成&#xff0c;却没生效&#xff0c;请检查插件的启用状态是否是启用状态&#xff0c; 以某个route配置的限速插件&#xff08;limit-req&#xff09;为例 1.打开dashboad-->路由-->某个路由-->更多-->查看&#xff0c; 查看配置&#xff0c;实际未启用…

C语言之进制转换

C语言之进制转换 一、引言二、十进制与二进制、八进制、十六进制三、二进制与八进制、十六进制四、八进制与十六进制 一、引言 在C语言中&#xff0c;经常使用的整数的进制有十进制、二进制、十六进制&#xff08;在C语言中以0x或0X为前缀&#xff09;、八进制&#xff08;在C…

PTA-感染人数

设某住宿区域是一个nn的方阵&#xff0c;方阵中的每个小方格为一个房间&#xff0c;房间里可能住一个人&#xff0c;也可能空着。第一天&#xff0c;某些房间中住着的人得了一种高传染性的流感&#xff0c;以后每一天&#xff0c;得流感的人会使其邻居&#xff08;住在其上、下…

【重点!!!】【贪心】45.跳跃游戏II

题目 法1&#xff1a;贪心 贪心是最优解法&#xff0c;必须掌握&#xff01;重点理解&#xff0c;看B站视频辅助&#xff01;&#xff01;&#xff01; 在具体的实现中&#xff0c;我们维护当前能够到达的最大下标位置&#xff0c;记为边界。我们从左到右遍历数组&#xff0…

对接第三方统一登录接口时,调用对方接口在Nginx上报405响应码错误解决方法

1、先看我的Nginx的配置文件&#xff08;业务入口局部配置&#xff09; 2、正确的解决方式是在location代码块中添加一行代码&#xff0c;【error_page 405 200 $request_uri;】如下所示&#xff1a; 3、接口测试 4、备注&#xff1a;如果报以下错误&#xff0c;是因为Nginx中…

【多线程及高并发 三】volatile synchorized 详解

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是若明天不见&#xff0c;BAT的Java高级开发工程师&#xff0c;CSDN博客专家&#xff0c;后端领域优质创作者 &#x1f4d5;系列专栏&#xff1a;多线程及高并发系列 &#x1f4d5;其他专栏&#xff1a;微服务框架系列、…
最新文章