QTを使用してlinux上で複数のUディスクをマウントすることを識別する
11056 ワード
背景:Uディスクマウント自体linuxに対してudevのようなツールサポートがあります.しかしudevマウントルールに依存しているため、あまりコントロールできない場合があります(実際に私が遭遇した問題は、デバイス端末にUディスクを挿入して電源を入れ、Uディスクを認識できずマウントすることです.Uディスクを認識するには、もう一度挿抜する必要があります).だからコードを作成して検出してマウントすることにした.
1.Uディスクをマウントするのは、mkdirがディレクトリを作成し、mountコマンドを使用してマウントすることにほかならない.(ここではUディスクのデバイスノードが/dev/sda 1であると仮定する)
2.では、Uディスクのホットスワップをどうやって検出しますか?タイマポーリングを使用して、/devディレクトリのデバイスノードの変化を検出し、ホットスワップを実現できます.この方法は実行可能ですが、リソースがかかりすぎて、お勧めしません.私がここで使っているのはQTが持っているクラス------QFileSystemWatcherです.ちょっとこのクラスを話してください.QFileSystemWatcherは、指定されたパスのリストを監視することで、ファイルシステム内のファイルとディレクトリの変更を監視します.addPath()関数を呼び出すと、特定のファイルまたはディレクトリを監視できます.複数のパスを監視する必要がある場合は、addPaths()を使用します.既存のパスは、removePath()およびremovePaths()関数を使用して除去されます.QFileSystemWatcherは、QFileSystemWatcherに追加されたファイルで使用可能なfiles()関数にアクセスするパスをチェックし、ディレクトリはdirectories()関数にアクセスします.ファイルが変更されたり、名前が変更されたり、ディスクから削除されたりすると、file Changed()信号が表示されます.同様に、ディレクトリまたはそのコンテンツが変更または削除されると、directoryChanged()信号が送信されます.ファイルの名前が変更されたり、ハードディスク(HDD)から削除されたりすると、ディレクトリがディスクから削除されたりすると、QFileSystemWatcherは監視を停止します.一時的なオブジェクトを定義するだけでなく、newがオブジェクトを出す必要があります.そうしないと、モニタリングの効果が得られません.実はこのクラスはlinux自身のinotifyツールに依存しています.
3.このような考え方は明らかになった.QFileSystemWatcherというクラスで/devディレクトリの変化をモニタリングし、検出された信号でUディスクのデバイス情報を取得します.そして情報を入手した後、デバイスをマウントまたはアンインストールする操作を行います.4.では、どのようにしてUSBデバイスの情報を取得しますか?ここで使用する方法は、linuxのblkidコマンドを使用して、コマンドをコンソールに出力するUディスクデバイス情報を取得し、必要なUディスクデバイス情報を解析することである.
5.では、コマンドを実行した後、コンソール情報をどのように取得しますか?ここで使用するQTのQprocessという類;6.では、コンソール情報を取得した後、必要なUディスク情報をどのように解析しますか?ここではQTのQRegExpを用い,正規表現で解析する.注意:a.blkidというコマンドは必ず-c/dev/nullというパラメータを使用します.追加しないとblkidというコマンドは/devディレクトリの下で一時ファイルを生成するからです.blkid.tab .blkid.tab.oldこれは、/devディレクトリの下でファイルが作成されたこと、すなわち/devディレクトリが変更されたことに相当し、これはQFileSystemWatcherに影響を与えるモニタリングを混同する.b.デバイスの電源を入れるときは、コマンドmount-t tmpfs none/mntを実行して、/mntディレクトリを一時ファイルシステムにマウントすることが望ましい.電源を切ると、/mntディレクトリの下のすべてのファイルが空になります.c.優盤がfat 32形式の場合、ボリュームラベルが中国語の場合、linuxに文字化けしが表示されます.(これはトランスコードで解決できるそうですが、私は成功しませんでした);ntfs形式のUディスクの場合、中国語のボリュームラベルは正常に表示されます.だから、ここでfat 32の優盤なら、私は帰ってそのUUIDを表示します.ubuntuもそうしました.
はい、基本的な考え方はもう終わりました.直接コードをつけましょう.
UdiskWatcher.cpp
1.Uディスクをマウントするのは、mkdirがディレクトリを作成し、mountコマンドを使用してマウントすることにほかならない.(ここではUディスクのデバイスノードが/dev/sda 1であると仮定する)
mkdir -p /mnt/usb
mount /dev/sda1 /mnt/usb // mount , U U
2.では、Uディスクのホットスワップをどうやって検出しますか?タイマポーリングを使用して、/devディレクトリのデバイスノードの変化を検出し、ホットスワップを実現できます.この方法は実行可能ですが、リソースがかかりすぎて、お勧めしません.私がここで使っているのはQTが持っているクラス------QFileSystemWatcherです.ちょっとこのクラスを話してください.QFileSystemWatcherは、指定されたパスのリストを監視することで、ファイルシステム内のファイルとディレクトリの変更を監視します.addPath()関数を呼び出すと、特定のファイルまたはディレクトリを監視できます.複数のパスを監視する必要がある場合は、addPaths()を使用します.既存のパスは、removePath()およびremovePaths()関数を使用して除去されます.QFileSystemWatcherは、QFileSystemWatcherに追加されたファイルで使用可能なfiles()関数にアクセスするパスをチェックし、ディレクトリはdirectories()関数にアクセスします.ファイルが変更されたり、名前が変更されたり、ディスクから削除されたりすると、file Changed()信号が表示されます.同様に、ディレクトリまたはそのコンテンツが変更または削除されると、directoryChanged()信号が送信されます.ファイルの名前が変更されたり、ハードディスク(HDD)から削除されたりすると、ディレクトリがディスクから削除されたりすると、QFileSystemWatcherは監視を停止します.一時的なオブジェクトを定義するだけでなく、newがオブジェクトを出す必要があります.そうしないと、モニタリングの効果が得られません.実はこのクラスはlinux自身のinotifyツールに依存しています.
3.このような考え方は明らかになった.QFileSystemWatcherというクラスで/devディレクトリの変化をモニタリングし、検出された信号でUディスクのデバイス情報を取得します.そして情報を入手した後、デバイスをマウントまたはアンインストールする操作を行います.4.では、どのようにしてUSBデバイスの情報を取得しますか?ここで使用する方法は、linuxのblkidコマンドを使用して、コマンドをコンソールに出力するUディスクデバイス情報を取得し、必要なUディスクデバイス情報を解析することである.
blkid -d -c /dev/null
/dev/mmcblk3p2: UUID="bbe3ba31-a0cb-4982-86dd-959f9e01d32c" TYPE="ext2"
/dev/sda1: UUID="D87072FE7072E324" TYPE="ntfs"
/dev/sdb4: LABEL="Ubuntu 16.0" UUID="B4FE-5315" TYPE="vfat"
/dev/sdc1: LABEL=" " UUID="12E2766CE27653C7" TYPE="ntfs"
5.では、コマンドを実行した後、コンソール情報をどのように取得しますか?ここで使用するQTのQprocessという類;6.では、コンソール情報を取得した後、必要なUディスク情報をどのように解析しますか?ここではQTのQRegExpを用い,正規表現で解析する.注意:a.blkidというコマンドは必ず-c/dev/nullというパラメータを使用します.追加しないとblkidというコマンドは/devディレクトリの下で一時ファイルを生成するからです.blkid.tab .blkid.tab.oldこれは、/devディレクトリの下でファイルが作成されたこと、すなわち/devディレクトリが変更されたことに相当し、これはQFileSystemWatcherに影響を与えるモニタリングを混同する.b.デバイスの電源を入れるときは、コマンドmount-t tmpfs none/mntを実行して、/mntディレクトリを一時ファイルシステムにマウントすることが望ましい.電源を切ると、/mntディレクトリの下のすべてのファイルが空になります.c.優盤がfat 32形式の場合、ボリュームラベルが中国語の場合、linuxに文字化けしが表示されます.(これはトランスコードで解決できるそうですが、私は成功しませんでした);ntfs形式のUディスクの場合、中国語のボリュームラベルは正常に表示されます.だから、ここでfat 32の優盤なら、私は帰ってそのUUIDを表示します.ubuntuもそうしました.
はい、基本的な考え方はもう終わりました.直接コードをつけましょう.
UdiskWatcher.cpp
#include "UdiskWatcher.h"
#include
#include
#include
#include
#include
// U
#define USB_COUNT 10
USBDeviceInfo::USBDeviceInfo()
: strDev("")
, strUUID("")
, strLABEL("")
, strTYPE("")
, isBusy(false)
{
}
bool USBDeviceInfo::operator==(const USBDeviceInfo &value)
{
return (strUUID == value.strUUID);
}
UdiskWatcher::UdiskWatcher(QObject *parent)
: QObject(parent)
, m_systemWatcher(NULL)
{
m_systemWatcher = new QFileSystemWatcher(this);
if (!m_systemWatcher->addPath("/dev"))
{
qDebug() << "fileSystemWatcher invalid path!";
}
// QFileSystemWathcher U , U ;
// UdiskWatcher U , U
udiskHandle();
connect(m_systemWatcher, &QFileSystemWatcher::directoryChanged, this, &UdiskWatcher::udiskHandle);
}
UdiskWatcher::~UdiskWatcher()
{
}
void UdiskWatcher::udiskHandle()
{
refreshUSBdeviceList();
int devListSize = m_usbDevList.size();
int count = 0;
for (int i = 0; i < devListSize; i++)
{
if (m_usbDevListMounted.contains(m_usbDevList.at(i)))
{
count++;
}
}
qDebug("count = %d , devListSize = %d , m_usbDevListMounted.size() = %d", count, devListSize, m_usbDevListMounted.size());
if ((count == m_usbDevListMounted.size()) && (count == devListSize))
{
qDebug("no usb changed");
return; // list ,
}
QList usbDevListAdded; // U , U
QList usbDevListRemoved; // U , U
usbDevListAdded.clear();
usbDevListRemoved.clear();
for (int j = 0; j < m_usbDevListMounted.size(); j++)
{
if (!m_usbDevList.contains(m_usbDevListMounted.at(j)))
{
usbDevListRemoved.append(m_usbDevListMounted.at(j));
}
}
qDebug("need to umount usb count = %d", usbDevListRemoved.size());
// U
for (int j = 0; j < usbDevListRemoved.size(); j++)
{
umountUsb(usbDevListRemoved.at(j));
}
if (m_usbDevListMounted.size() < USB_COUNT)
{
for (int i = 0; i < devListSize; i++)
{
if (!m_usbDevListMounted.contains(m_usbDevList.at(i)))
{
usbDevListAdded.append(m_usbDevList.at(i));
}
}
qDebug("need to mount usb count = %d", usbDevListAdded.size());
// U
for (int i = 0; i < usbDevListAdded.size(); i++)
{
mountUsb(usbDevListAdded.at(i));
}
}
}
QList UdiskWatcher::getCurrentUSBDevice()
{
return m_usbDevListMounted;
}
bool UdiskWatcher::mountUsb(USBDeviceInfo dev)
{
qDebug("DeviceManager::mountUsb
");
#ifndef _WIN32
QString output;
QString usbName;
// U ntfs , ; U fat32 , UUID; ubuntu ;
if (dev.strTYPE == "ntfs" && !dev.strLABEL.isEmpty())
{
usbName = "/mnt/" + dev.strLABEL;
}
else
{
usbName = "/mnt/" + dev.strUUID;
}
if (QFile::exists(usbName))
{
qDebug() << "derectory has exist!";
return true;
}
if (!myProcess("mkdir", QStringList() << "-p" << usbName, output))
{
qDebug() << "mkdir usb derectory failed!";
return false;
}
if (!myProcess("/bin/mount", QStringList() << "-o" << "sync" << "-o" << "shortname=mixed" << "-o" << "utf8=yes" << dev.strDev << usbName, output))
{
qDebug() << "mount usb failed!";
return false;
}
if (!myProcess("touch", QStringList() << usbName, output))
{
qDebug() << "touch usb derectory failed!";
return false;
}
m_usbDevListMounted.append(dev);
qDebug("DeviceManager::mountUsb success! m_usbDevListMounted.size = %d
", m_usbDevListMounted.size());
return true;
#else
Q_UNUSED(dev)
return false;
#endif
}
bool UdiskWatcher::umountUsb(USBDeviceInfo dev)
{
qDebug("DeviceManager::umountUsb
");
#ifndef _WIN32
QString output;
QString usbName;
if (dev.strTYPE == "ntfs" && !dev.strLABEL.isEmpty())
{
usbName = "/mnt/" + dev.strLABEL;
}
else
{
usbName = "/mnt/" + dev.strUUID;
}
if (!QFile::exists(usbName))
{
qDebug() << "derectory has not exist!";
return true;
}
if (!myProcess("/bin/umount", QStringList() << usbName, output))
{
qDebug() << "umount usb failed!";
return false;
}
if (!myProcess("rmdir", QStringList() << usbName, output))
{
qDebug() << "rmdir usb derectory failed!";
return false;
}
m_usbDevListMounted.removeAll(dev);
qDebug("DeviceManager::umountUsb success! m_usbDevListMounted.size = %d
", m_usbDevListMounted.size());
return true;
#else
return false;
#endif
}
void UdiskWatcher::refreshUSBdeviceList()
{
#ifndef _WIN32
m_usbDevList.clear();
QString output;
myProcess("blkid", QStringList() << "-d" << "-c" << "/dev/null", output);
// , U
QStringList itemList;
myRegExp("/dev/sd[a-z].*\
", output, itemList);
for (int i = 0; i < itemList.size(); i++)
{
USBDeviceInfo info;
QStringList tempList;
if (myRegExp("/dev/sd[a-z][1-9]", itemList.at(i), tempList) > 0)
{
info.strDev = tempList.at(0);
tempList.clear();
}
if (myRegExp("LABEL=\".*\"", itemList.at(i), tempList) > 0)
{
int size = tempList.at(0).size();
info.strLABEL = tempList.at(0).mid(7, (size-8));
tempList.clear();
}
if (myRegExp("UUID=\".*\"", itemList.at(i), tempList) > 0)
{
int size = tempList.at(0).size();
info.strUUID = tempList.at(0).mid(6, (size-7));
tempList.clear();
}
if (myRegExp("TYPE=\".*\"", itemList.at(i), tempList) > 0)
{
int size = tempList.at(0).size();
info.strTYPE = tempList.at(0).mid(6, (size-7));
tempList.clear();
}
m_usbDevList.append(info);
}
if (m_usbDevList.size() < 1)
{
qDebug() << " u !";
return;
}
#endif
}
int UdiskWatcher::myRegExp(const QString pattern, const QString &text, QStringList &list)
{
QRegExp regExp;
int capCount = 0;
int pos = 0;
if (pattern.isEmpty() || text.isEmpty())
{
return -1;
}
regExp.setMinimal(true);
regExp.setPattern(pattern);
regExp.indexIn(text);
list.clear();
while ((pos = regExp.indexIn(text, pos)) != -1)
{
list.push_back(regExp.cap(0));
pos += regExp.matchedLength();
capCount++;
}
return capCount;
}
bool UdiskWatcher::myProcess(QString cmd, QStringList param, QString &output)
{
QProcess process;
process.start(cmd, param);
//
if (!process.waitForStarted())
{
qDebug() << "
";
return false;
}
process.closeWriteChannel();
//
QByteArray procOutput;
while (!process.waitForFinished(300))
{
qDebug() << "
";
return false;
}
procOutput = process.readAll();
output = procOutput;
return true;
}