(7)Qt---文件IO

news2024/9/24 3:22:29

目录

1. QFileDialog 文件选择对话框**

2. QFileInfo 文件信息类**

3. QFile 文件读写类***

4. UI与耗时操作**

5. QThread 线程类

5.1 复现阻塞

5.2 新建并启动子线程

5.3 异步刷新

5.4 停止线程


1. QFileDialog 文件选择对话框**

操作系统会提供一个统一样式的文件选择对话框,QFileDialog类可以直接调用系统自带的文件选择对话框。

QFileDialog继承自QDialog,这样的类直接使用静态成员函数调用。

// 参数1:父对象
// 参数2:标题栏
// 参数3:打开QFileDialog时所在的根目录,默认值为工作目录
// 参数4:文件格式过滤器
// 返回值:文件路径,选择失败返回空字符串
QString QFileDialog::getSaveFileName|getOpenFileName(
                             QWidget * parent = 0, 
                             const QString & caption = QString(),
                             const QString & dir = QString(),    
                             const QString & filter = QString()) [static]

2. QFileInfo 文件信息类**

QFileInfo类用于获取文件信息。

相关函数如下:

// 构造函数
// 参数是文件路径,如果路径无效,对象仍然会创建成功
QFileInfo::QFileInfo(const QString & file)
// 判断对应路径下的文件是否存在
bool QFileInfo::exists() const
// 创建时间
QDateTime QFileInfo::created() const
// 上次修改时间
QDateTime QFileInfo::lastModified() const
// 上次读取时间
QDateTime QFileInfo::lastRead() const
// 是否可读
bool QFileInfo::isReadable() const
// 是否可写
bool QFileInfo::isWritable() const
// 获得文件大小,单位字节,如果文件不存在返回0
qint64 QFileInfo::size() const

更多API详见文档。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QFileInfo>
#include <QtWidgets>
#include <QDialog>
#include <QButtonGroup>
#include <QDateTime>
namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;
    QButtonGroup * group;
    //获得读取的路径、获得写出路径
    void getReadPath();
    void getWritePath();
    QString readPath; //要读取的路径
    QString writePath; //要存储的路径
    void showFileMessage();

private slots:
    //按钮组点击的槽函数
    void btnsClickedSlot(int);
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    group = new QButtonGroup(this);
    group->addButton(ui->pushButtonOpen,1);
    group->addButton(ui->pushButtonSave,2);
    group->addButton(ui->pushButtonCopy,3);

    connect(group,SIGNAL(buttonClicked(int)),this,SLOT(btnsClickedSlot(int)));
}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::getReadPath()
{
    //过滤器
    QString filter = "所有格式(*.*);;C++(*.h *.cpp)";
    //四个参数,见笔记
    QString path = QFileDialog::getOpenFileName(this,"打开","E:/",filter);
    if(path==""&& readPath==""){
        //引导用户进行正确的处理
        QMessageBox::warning(this,"提示","请选择有效路径!");
        return;
    }
    readPath = path;
    //展示
    if(path != "")
        ui->textBrowserOpen->clear();
    ui->textBrowserOpen->append(readPath);
}

void Dialog::getWritePath()
{
    //过滤器
    QString filter = "所有格式(*.*);;C++(*.h *.cpp)";
    //四个参数,见笔记
    QString path = QFileDialog::getSaveFileName(this,"打开","E:/",filter);
    if(path==""&& writePath==""){
        //引导用户进行正确的处理
        QMessageBox::warning(this,"提示","请选择有效路径!");
        return;
    }
    writePath = path;
    //展示
    if(path != "")
        ui->textBrowserOpen->clear();
    ui->textBrowserOpen->append(writePath);
}

void Dialog::showFileMessage()
{
    //创建文件信息类对象
    QFileInfo info(readPath);
    //获得创建时间
    QString time = info.created().toString("yyyy-MM-dd hh:mm:ss");
    ui->textBrowserOpen->append(time.prepend("创建时间:"));
    //是否可读
    bool result = info.isReadable();
    if(result)
        ui->textBrowserOpen->append("可读");
    else
        ui->textBrowserOpen->append("不可读");
    //获取文件大小
    qint64 size = info.size();
    QString text;
    text.setNum(size).prepend("文件大小:").append("字节");
    ui->textBrowserOpen->append(text);
}

void Dialog::btnsClickedSlot(int id)
{
    if(id==1){
        getReadPath();

    }else if(id==2){
        getWritePath();

    }else if(id==3){

    }
}

 

3. QFile 文件读写类***

用于读写文件,需要注意的是QFile间接继承QIODevice类,QIODevice类是Qt所有IO类的基类,QIODevice类中规定了一些最基础的IO接口,本节讲解的这些接口,在后续其它IO类中也可以使用。

QFile的常用函数如下:

// 参数为文件路径
QFile::QFile(const QString & name)
// 判断对应路径下的文件是否存在
bool QFile::exists() const
// 打开数据流
// 参数为打开模式
// 返回值为打开的结果
bool QIODevice::open(OpenMode mode) [virtual]
// 读取的数据流是否位于末端
bool QIODevice::atEnd() const [virtual]
// 读取maxSize个字节到返回值的字节数组对象中
// 注意maxSize表示最大数量,不一定是实际数量
QByteArray QIODevice::read(qint64 maxSize)
// 输出到制定的位置
// 参数是输出的内容
// 返回值是实际的输出量
qint64 QIODevice::write(const QByteArray & byteArray)
// 清空输出流的缓存数据,返回值是结果
bool QFileDevice::flush()
// 关闭数据流
void QIODevice::close() [virtual]
// 获取剩余可读的数据量
qint64 QIODevice::size() const [virtual]

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QFileInfo>
#include <QtWidgets>
#include <QDialog>
#include <QButtonGroup>
#include <QDateTime>
namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;
    QButtonGroup * group;
    //获得读取的路径、获得写出路径
    void getReadPath();
    void getWritePath();
    QString readPath; //要读取的路径
    QString writePath; //要存储的路径
    void showFileMessage();
    void copy();

private slots:
    //按钮组点击的槽函数
    void btnsClickedSlot(int);
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    group = new QButtonGroup(this);
    group->addButton(ui->pushButtonOpen,1);
    group->addButton(ui->pushButtonSave,2);
    group->addButton(ui->pushButtonCopy,3);

    connect(group,SIGNAL(buttonClicked(int)),
            this,SLOT(btnsClickedSlot(int)));
}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::getReadPath()
{
    // 过滤器
    QString filter = "所有格式(*.*);;C++(*.h *.cpp)";
    // 四个参数,见笔记
    QString path = QFileDialog::getOpenFileName(this,"打开","E:/",filter);
    if(path=="" && readPath=="")
    {
        // 引导用户进行正确的处理
        QMessageBox::warning(this,"提示","请选择有效路径!");
        return;
    }
    readPath = path;
    // 展示
    if(path != "")
        ui->textBrowserOpen->clear();
    ui->textBrowserOpen->append(readPath);
    showFileMessage(); // 展示文件信息
}

void Dialog::getWritePath()
{
    // 过滤器
    QString filter = "所有格式(*.*);;C++(*.h *.cpp)";
    // 四个参数,见笔记
    QString path = QFileDialog::getSaveFileName(this,"保存","E:/",filter);
    if(path=="" && writePath=="")
    {
        // 引导用户进行正确的处理
        QMessageBox::warning(this,"提示","请选择有效路径!");
        return;
    }
    writePath = path;
    // 展示
    if(path != "")
        ui->textBrowserSave->clear();
    ui->textBrowserSave->append(writePath);
}

void Dialog::showFileMessage()
{
    // 创建文件信息类对象
    QFileInfo info(readPath);
    // 获得创建时间
    QString time = info.created().toString("yyyy-MM-dd hh:mm:ss");
    ui->textBrowserOpen->append(time.prepend("创建时间:"));
    // 是否可读
    bool result = info.isReadable();
    if(result)
        ui->textBrowserOpen->append("可读");
    else
        ui->textBrowserOpen->append("不可读");
    // 获取文件大小
    qint64 size = info.size();
    QString text;
    text.setNum(size).prepend("文件大小:").append("字节");
    ui->textBrowserOpen->append(text);
}

void Dialog::copy()
{
    // 读写的对象
    QFile readFile(readPath);
    QFile writeFile(writePath);
    if(!readFile.exists())
    {
        QMessageBox::warning(this,"提示","请选择有效的读写路径!");
        return;
    }
    // 屏蔽拷贝按钮
    ui->pushButtonCopy->setEnabled(false);
    ui->pushButtonCopy->setText("拷贝中");
    // 使用只读模式打开数据流
    readFile.open(QIODevice::ReadOnly);
    writeFile.open(QIODevice::WriteOnly);

    qint64 totalSize = readFile.size(); // 文件总大小
    qint64 hasCopied = 0; // 已经读写的数据量

    QByteArray buffer; // “小推车”

    while(!readFile.atEnd()) // 循环读取
    {
        buffer = readFile.read(1024); // 一次读取1kb
        // 输出
        hasCopied += writeFile.write(buffer);
        // 计算百分比
        int value = hasCopied*100/totalSize;
        // 更新UI显示
        ui->progressBar->setValue(value);
    }

    // 收尾
    writeFile.flush();
    writeFile.close();
    readFile.close();
    // 屏蔽拷贝按钮
    ui->pushButtonCopy->setEnabled(true);
    ui->pushButtonCopy->setText("开始拷贝");
    QMessageBox::information(this,"通知",writePath.prepend("文件拷贝完成,请查看"));
}

void Dialog::btnsClickedSlot(int id)
{
    if(id == 1)
    {
        getReadPath();
    }else if(id == 2)
    {
        getWritePath();
    }else if(id == 3)
    {
        copy();
    }
}

运行结果:

 

4. UI与耗时操作**

Qt项目在默认的情况下只有一个线程,这个线程负责UI显示与用户的人机交互等程序运行所需的基础操作,因此这个线程也被称为主线程。

但是如果在主线程中执行一些耗时操作(例如IO、复杂算法等),会导致主线程原本的操作阻塞,无法及时响应,因此出现程序假死的现象。

此时强行关闭程序,由于耗时操作正在处理,导致关闭的命令也无法及时执行,操作系统检测到某个应用程序关闭无效,启动操作系统的保护机制,弹出对话框窗口引导用户是否强行关闭。

 解决方法是新启动一个线程,让这个线程执行耗时操作,这样的线程被称为子线程。

5. QThread 线程类

5.1 复现阻塞

QThread类是Qt的线程类,其中使用睡眠函数可以非常方便的模仿耗时操作的效果。

// 使当前线程睡眠一段时间
// 参数为睡眠时间,单位毫秒
void QThread::msleep(unsigned long msecs) [static]

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QtWidgets>
//线程类头文件
#include <QThread>
namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;

private slots:
    void btnSleepClickedSlot();
    void btnBoxClickedSlot();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    connect(ui->pushButtonBox,SIGNAL(clicked()),this,SLOT(btnBoxClickedSlot()));
    connect(ui->pushButtonSleep,SIGNAL(clicked()),this,SLOT(btnSleepClickedSlot()));
}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::btnSleepClickedSlot()
{
    //睡眠10s
    QThread::msleep(10000);
}

void Dialog::btnBoxClickedSlot()
{
    QMessageBox::information(this,"随便","无所谓");
}

 

5.2 新建并启动子线程

操作步骤如下所示:

1. 在Qt Creator中,选中项目名称,鼠标右键,点击“添加新文件”。

2. 在弹出的窗口中根据下图所示进行操作。

3. 在弹出的窗口中,依次输入类名(大驼峰)、基类名(QThread),选择类型信息(继承自QObject)后,点击“下一步”。

4. 在项目管理界面点击“完成”。可以在项目中看到已经创建的头文件和源文件。

5. 进入到自定义线程类的头文件,声明run函数。

// 子线程执行的起始点,在子线程对象调用start函数后,此函数自动被调用
// 此函数执行完成后,子线程也执行完成
void QThread::run() [virtual protected]

 

6. 在自定义线程类的源文件中,定义run函数。

7. 在run函数中添加子线程要执行的耗时操作代码。

8. 在主线程中创建子线程对象,调用start函数后开始子线程开始执行。

程序代码:

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QDebug>

class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = 0);

protected:
    void run(); // 声明run函数 --1

signals:

public slots:

};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"

MyThread::MyThread(QObject *parent) :
    QThread(parent)
{
}

// 定义run函数 --2
void MyThread::run()
{
    qDebug() << "子线程开始" ;
    // 睡眠10s
    msleep(10000);
    qDebug() << "子线程结束" ;  //--3
}

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QtWidgets>
// 子线程头文件
#include "mythread.h"

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;

private slots:
    void btnSleepClickedSlot();
    void btnBoxClickedSlot();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    connect(ui->pushButtonBox,SIGNAL(clicked()),
            this,SLOT(btnBoxClickedSlot()));
    connect(ui->pushButtonSleep,SIGNAL(clicked()),
            this,SLOT(btnSleepClickedSlot()));
}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::btnSleepClickedSlot()
{
    // 创建子线程对象
    MyThread *mt = new MyThread(this);
    // 开始执行子线程
    mt->start();     //--5
}

void Dialog::btnBoxClickedSlot()
{
    QMessageBox::information(this,"随便","无所谓");
}

运行结果:

 

5.3 异步刷新

在开发的过程中,经常遇到下面的场景:

子线程执行耗时操作,主线程显示耗时操作的信息。

此时需要子线程通过信号槽传参发送数据给主线程。需要注意的是,子线程只能执行耗时操作,主线程只能执行非耗时操作。

copythread.h

#ifndef COPYTHREAD_H
#define COPYTHREAD_H

#include <QThread>

class CopyThread : public QThread
{
    Q_OBJECT
public:
    explicit CopyThread(QObject *parent = 0);
//声明run函数
protected:
    void run();

signals:
    // 自定义信号
    void valueSignal(int);

public slots:

};

#endif // COPYTHREAD_H

copythread.cpp

#include "copythread.h"

CopyThread::CopyThread(QObject *parent) :
    QThread(parent)
{
}
//定义run函数
void CopyThread::run()
{
    // 模拟文件拷贝的耗时操作
    for(int i=0;i<=100;i++)
    {
        msleep(50); // 模拟拷贝消耗时间
        emit valueSignal(i); // 发射进度值
    }
}

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
// 自定义线程类
#include "copythread.h"

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;

private slots:
    void btnClickedSlot(); // 按钮点击的槽函数
    void valueSlot(int); // 接收子线程信号参数的槽函数
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    // 连接按钮点击的信号槽
    connect(ui->pushButton,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));
}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::btnClickedSlot()
{
    // 创建并启动子线程
    CopyThread *ct = new CopyThread(this);
    // 连接两个线程之间的信号槽
    connect(ct,SIGNAL(valueSignal(int)),
            this,SLOT(valueSlot(int)));
    ct->start();
}

void Dialog::valueSlot(int value)
{
    // 更新进度条
    ui->progressBar->setValue(value);
}

ui界面:

运行结果:

 

 

5.4 停止线程

介绍两种停止线程运行的方式:

  • 调用terminate函数,不推荐使用,因为这种方式是强制停止线程运行,可能导致占用的资源无法释放。
void QThread::terminate() [slot]
  • 使用标志位,耗时操作往往伴随着循环,可以给循环体增加一个标志位,通过控制这个标志位的值使循环正常跳出,从而使run函数正常结束。

 copythread.h

#ifndef COPYTHREAD_H
#define COPYTHREAD_H

#include <QThread>

class CopyThread : public QThread
{
    Q_OBJECT
public:
    explicit CopyThread(QObject *parent = 0);
    bool isRunning = true; // 是否运行的标志位,先不封装了

protected:
    void run();

signals:
    // 自定义信号
    void valueSignal(int);

public slots:

};

#endif // COPYTHREAD_H

copythread.cpp

#include "copythread.h"

CopyThread::CopyThread(QObject *parent) :
    QThread(parent)
{
}

void CopyThread::run()
{
    // 模拟文件拷贝的耗时操作
    for(int i=0;i<=100 && isRunning;i++)
    {
        msleep(50); // 模拟拷贝消耗时间
        emit valueSignal(i); // 发射进度值
    }
}

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
// 自定义线程类
#include "copythread.h"

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;
    CopyThread *ct = NULL;

private slots:
    void btnClickedSlot(); // 按钮点击的槽函数
    void valueSlot(int); // 接收子线程信号参数的槽函数
    void btnFClickedSlot(); // 标志位停止的槽函数
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    // 连接按钮点击的信号槽
    connect(ui->pushButton,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));
}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::btnClickedSlot()
{
    // 创建并启动子线程
    ct = new CopyThread(this);
    // 连接两个线程之间的信号槽
    connect(ct,SIGNAL(valueSignal(int)),
            this,SLOT(valueSlot(int)));
    // 连接强制停止的槽函数
    connect(ui->pushButtonT,SIGNAL(clicked()),
            ct,SLOT(terminate()));
    // 连接温柔停止的槽函数
    connect(ui->pushButtonF,SIGNAL(clicked()),
            this,SLOT(btnFClickedSlot()));
    ct->start();
}

void Dialog::valueSlot(int value)
{
    // 更新进度条
    ui->progressBar->setValue(value);
}

void Dialog::btnFClickedSlot()
{
    if(ct != NULL)
        // 温柔停止
        ct->isRunning = false;
}

ui界面:

 运行结果:

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从本地到云端:豆瓣如何使用 JuiceFS 实现统一的数据存储

豆瓣成立于 2005 年&#xff0c;是中国最早的社交网站之一。在 2009 到 2019 的十年间&#xff0c;豆瓣数据平台经历了几轮变迁&#xff0c;形成了 DPark Mesos MooseFS 的架构。 由机房全面上云的过程中&#xff0c;原有这套架构并不能很好的利用云的特性&#xff0c;豆瓣需…

少林派问题汇总

少林派问题汇总&#xff1a; Q: A:缺少bmodel,没有指定bmodel的路径&#xff0c;测试图片不在同一文件路径下 复制过来就解决了 Q: docker容器下运行./install_lib.sh nntc会rm不到文件怎么回事? A&#xff1a;文件已经被删除 Q: 我将pytorch的模型用export工具转换成.torch…

聚焦丨酷雷曼荣列XRMA联盟成员单位

自“元宇宙”概念兴起之初&#xff0c;酷雷曼VR所属北京同创蓝天云科技有限公司就积极布局、探索和实践。2022年12月&#xff0c;酷雷曼VR成功加入虚拟现实与元宇宙产业联盟&#xff08;XRMA&#xff09;&#xff0c;正式被接纳为联盟成员单位&#xff0c;意味着酷雷曼公司将进…

详细版易学版TypeScript - 元组 枚举详解

一、元组(Tuple) 数组:合并了相同类型的对象 const myArr: Array<number> [1, 2, 3]; 元组(Tuple):合并了不同类型的对象 // 定义元组时就要确定好数据的类型&#xff0c;并一一对应 const tuple: [number, string] [12, "hi"]; // 添加内容时&#xff0c;不…

代码随想录算法训练营day35 | 860.柠檬水找零,406.根据身高重建队列,452. 用最少数量的箭引爆气球

代码随想录算法训练营day35 | 860.柠檬水找零&#xff0c;406.根据身高重建队列&#xff0c;452. 用最少数量的箭引爆气球 860.柠檬水找零406.根据身高重建队列452. 用最少数量的箭引爆气球 860.柠檬水找零 教程视频&#xff1a;https://www.bilibili.com/video/BV12x4y1j7DD/…

3.SpringBoot开发实用篇

SpringBoot开发实用篇 ​ 开发实用篇中因为牵扯到SpringBoot整合各种各样的技术&#xff0c;由于不是每个小伙伴对各种技术都有所掌握&#xff0c;所以在整合每一个技术之前&#xff0c;都会做一个快速的普及&#xff0c;这样的话内容整个开发实用篇所包含的内容就会比较多。各…

推荐系统综述

这里写目录标题 推荐系统架构1、传统推荐方式1.1 基于内容推荐&#xff08;Content-Based recommendation&#xff0c;CB&#xff09;1.2 协同过滤推荐&#xff08;Collaborative Filtering recommendation&#xff0c; CF&#xff09;1.2.0 UserCF举例&#xff1a;1. 2. 1 基于…

window-2016服务器;服务——活动目录

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a;小刘主页 ♥️每天分享云计算网络运维课堂笔记&#xff0c;努力不一定有收获&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️树高千尺&#xff0c;落叶归根人生不易&…

OpenCL编程指南-2.1HelloWorld

在windows下编写HelloWorld 按照前面文章搭建好OpenCL的环境https://blog.csdn.net/qq_36314864/article/details/130513584 main函数完成以下操作&#xff1a; 1&#xff09;在第一个可用平台上创建OpenCL上下文 2&#xff09;在第一个可用设备上创建命令队列 3&#xff09;…

第二期 | ICASSP 2023 论文预讲会

ICASSP 2023 论文预讲会是由CCF语音对话与听觉专委会、语音之家主办&#xff0c;旨在为学者们提供更多的交流机会&#xff0c;更方便、快捷地了解领域前沿。活动将邀请 ICASSP 2023 录用论文的作者进行报告交流。 ICASSP 2023 论文预讲会邀请到清华大学人机语音交互实验室&…

单细胞跨模态分析综述

单细胞技术的最新进展使跨模态和组织位置的细胞高通量分子分析成为可能。单细胞转录组数据现在可以通过染色质可及性、表面蛋白表达、适应性免疫受体库分析和空间信息进行补充。跨模态单细胞数据的可用性越来越高&#xff0c;推动出新的计算方法&#xff0c;以帮助科学家获得生…

图的遍历——深度优先搜索(DFS)与广度优先搜索(BFS)(附带C语言源码)

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️数据结构与算法】 学习名言&#xff1a;天子重英豪&#xff0c;文章教儿曹。万般皆下品&#xff0c;惟有读书高——《神童诗劝学》 系列文章目录 第一章 ❤️ 学前知识 第二章 ❤️ 单向链表 第三章…

mysql数据迁移与同步常用解决方案总结

目录 一、前言 二、数据迁移场景 2.1 整库迁移 2.2 表数据迁移 2.3 mysql版本变更 2.4 mysql数据迁移至其他存储介质 2.5 自建数据到上云环境 2.6 mysql数据到其他国产数据库 三、数据库物理迁移实施方案 3.1 数据库物理迁移概述 3.1.1 物理迁移适用场景 3.1.2 物理…

杂记 2023.5.10

目录 韦伯和斯托亚科维奇是谁&#xff1f; 介绍一下kali FastDFS和Sentinel是什么&#xff1f; Inferno 找工作的影响因素 1. 背景&#xff1a; 2. 学习过程&#xff1a; 2.1 计算机基础&#xff1a; 2.2 语言&#xff1a; 2.3 数据库等&#xff1a; 2.4 JVM&#…

月薪17k需要什么水平?98年测试员的面试全过程…

我的情况 大概介绍一下个人情况&#xff0c;男&#xff0c;本科&#xff0c;三年多测试工作经验&#xff0c;懂python&#xff0c;会写脚本&#xff0c;会selenium&#xff0c;会性能&#xff0c;然而到今天都没有收到一份offer&#xff01;从年后就开始准备简历&#xff0c;年…

Linux操作系统如何查看CPU型号信息?一条命令搞定

Linux操作系统服务器如何查看CPU处理器信息&#xff1f;使用命令cat /proc/cpuinfo可以查看CPU详细信息&#xff0c;包括CPU核数、逻辑CPU、物理CPU个数、CPU是否启用超线程等&#xff0c;阿里云服务器网分享Linux服务器查看CPU信息命令&#xff1a; 目录 Linux服务器查看CPU…

Visual Studio Code 1.78 发布!

欢迎使用 Visual Studio Code 2023 年 4 月版。一些主要亮点包括&#xff1a; 辅助功能改进 - 更好的屏幕阅读器支持、新的音频提示。新颜色主题 - “现代”浅色和深色主题默认设置。配置文件模板 - Python、Java、数据科学等的内置模板。拖放选择器 - 选择您希望如何将项目链…

【AI】YOLOV2原理详解

1、简介 Yolov2采用了Darknet-19特征提取网络,包括19个卷积层和5个maxpooling层,网络结构如下: 也有尝试使用ResNet-50作为特征提取的模型,网络结构如下: 2、YOLOV2的改进 2.1 加入批归一化(Batch Nomalization) 对数据进行预处理(统一格式、均衡化、去噪等)…

隐语团队研究成果再创佳绩,两篇论文分别被USENIX ATC‘23和IJCAI‘23接收!

‍“USENIX ATC‍年度技术会议”&#xff08;USENIX ATC&#xff0c;USENIX Annual Technical Conference&#xff09;是计算机系统领域的顶级学术会议之一。本年度 USENIX ATC’23将于7月10日至12日在美国波士顿召开。本次会议共投稿353篇论文&#xff0c;接收65篇&#xff0c…

【Redis】电商项目秒杀问题之超卖问题与一人一单问题

目录 一、超卖问题 1、背景 2、产生原因以及线程安全问题 3、解决 1.悲观锁 2.乐观锁 4、新的问题 5、解决 二、一人一单 1、背景 2、产生原因以及线程安全问题 3、解决 4、新的问题----集群下的并发安全问题 5、解决 三、集群下的并发问题 1、说明 2、解决 一…