数值操作
将一个无符号数值转换为多个无符号字符
可以使用 C++ 中的位运算来实现将一个无符号数值转换为多个无符号字符。以下是示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#include <iostream>
int main() {
uint32_t value = 0x12345678;
// 将 value 转换为 char 数组
uint8_t data[4];
data[0] = (value >> 24) & 0xFF;
data[1] = (value >> 16) & 0xFF;
data[2] = (value >> 8) & 0xFF;
data[3] = value & 0xFF;
// 输出转换结果
std::cout << "Value: 0x" << std::hex << value << std::endl;
std::cout << "Data : {";
for (int i = 0; i < 4; ++i) {
std::cout << "0x" << std::hex << static_cast<int>(data[i]) << ",";
}
std::cout << "}" << std::endl;
return 0;
}
|
在这个示例代码中,我们首先定义了一个无符号数值 value
,其值为 0x12345678
。然后,我们使用位运算从高位到低位依次提取出 value
的每个字节,并存储在一个无符号字符数组 data
中。
最后,我们输出了 value
的原始值和转换结果。
将多个无符号字符转换为一个无符号数值
可以使用 C++ 中的位运算来实现将多个无符号字符转换为一个无符号数值。以下是示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include <iostream>
int main() {
uint8_t data[] = {0x12, 0x34, 0x56, 0x78};
// 将 data 转换为 uint32_t 数值
uint32_t value = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
// 输出转换结果
std::cout << "Data : {";
for (int i = 0; i < 4; ++i) {
std::cout << "0x" << std::hex << static_cast<int>(data[i]) << ",";
}
std::cout << "}" << std::endl;
std::cout << "Value: 0x" << std::hex << value << std::endl;
return 0;
}
|
在这个示例代码中,我们首先定义了一个无符号字符数组 data
,其中包含了四个无符号字符 {0x12, 0x34, 0x56, 0x78}
。然后,我们使用位运算将这些字符组合成一个无符号数值 value
,我们将 data
数组的第一个元素左移 24 位,第二个元素左移 16 位,第三个元素左移 8 位,最后一个元素不需要左移,然后将这四个值通过按位或操作组合成一个无符号数值。
最后,我们输出了 data
的原始值和转换结果。
将一个字符串转换为16进制数
可以使用标准库函数 strtol
来将一个字符串转换为一个 16 进制数。以下是一个简单的示例代码:
1
2
3
4
5
6
7
8
9
|
#include <stdio.h>
#include <stdlib.h>
int main() {
char *str = "1623";
long value = strtol(str, NULL, 16);
printf("0x%lx\n", value);
return 0;
}
|
在这个代码中,我们首先定义了一个指向字符串 "1623"
的指针 str
。然后,我们使用 strtol
函数将该字符串转换为一个长整型变量 value
。第二个参数 NULL
表示我们不需要指向已转换部分结尾的指针,在这种情况下我们不需要这个参数。第三个参数 16 表示我们希望将字符串解释为一个 16 进制数。
最后,我们使用 printf
函数打印 value
的值,并在前面添加 0x
以表示它是一个 16 进制数。
输出结果为:
将16进制数的字符串 转换为为 16进制的数字,每2个字符表示一个16进制数,如:char *str ="1623345F6B2A";
转换为char [6] = {0x16, 0x23, 0x34, 0x5F, 0x6B, 0x2A};
可以用下面的代码实现将16进制数的字符串转换为16进制的数字:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
#include <iostream>
#include <string>
const char* hex_chars = "0123456789ABCDEF";
int main() {
// 输入16进制数的字符串
std::string str = "1623345F6B2A";
// 计算输出数组的长度,每2个字符表示一个16进制数
size_t len = str.length() / 2;
// 分配输出数组的空间,每个元素大小为1字节
unsigned char* out = new unsigned char[len];
// 将输入的16进制数的字符串转换为16进制数
for (size_t i = 0; i < len; i++) {
int high = strchr(hex_chars, toupper(str[i * 2])) - hex_chars;
int low = strchr(hex_chars, toupper(str[i * 2 + 1])) - hex_chars;
out[i] = (high << 4) | low;
}
// 输出转换后的16进制数
std::cout << "Output: ";
for (size_t i = 0; i < len; i++) {
std::cout << "0x" << std::hex << (unsigned int)out[i] << " ";
}
std::cout << "\n";
// 释放输出数组的内存
delete[] out;
return 0;
}
|
这个示例代码使用了 strchr
函数来查找字符在 hex_chars
中的位置,然后将高位和低位组成一个16进制数存入输出数组中。最后,将输出数组中的16进制数输出到控制台上。
1
|
Output: 0x16 0x23 0x34 0x5f 0x6b 0x2a
|
文件操作
遍历一个文件夹
C++ 中遍历一个文件夹通常需要使用系统特定的 API。以下是使用 Windows API 实现遍历文件夹的示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#include <windows.h>
#include <iostream>
int main() {
LPCSTR path = "C:\\MyFolder"; // 指定要遍历的文件夹路径
// 构造查询条件
WIN32_FIND_DATAA findData;
HANDLE hFind = INVALID_HANDLE_VALUE;
char searchPath[MAX_PATH];
snprintf(searchPath, MAX_PATH, "%s\\*", path);
hFind = FindFirstFileA(searchPath, &findData);
if (hFind == INVALID_HANDLE_VALUE) {
std::cout << "Failed to find first file!\n";
return -1;
}
do {
if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
std::cout << "File Name: " << findData.cFileName << '\n';
}
} while (FindNextFileA(hFind, &findData) != 0);
FindClose(hFind);
return 0;
}
|
这个示例代码使用 FindFirstFileA
函数和 FindNextFileA
函数在指定的文件夹中查找文件。这些函数会返回一个包含文件信息的结构体,通过检查结构体中的 dwFileAttributes
成员可以确定该文件是否是一个目录。如果不是目录,则可以将其名称打印出来。
需要注意的是,此示例代码假设文件夹路径为 ASCII 字符串,因此使用了 LPCSTR
和 snprintf
函数。如果您的文件夹路径包含 Unicode 字符,可以使用 LPCWSTR
和 snwprintf
函数代替。
如果文件夹路径包含 Unicode 字符,需要使用 wchar_t
类型和 Windows API 中对应的 Unicode 版本。以下是实现遍历文件夹的示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#include <windows.h>
#include <iostream>
int main() {
LPCWSTR path = L"C:\\MyFolder"; // 指定要遍历的文件夹路径
// 构造查询条件
WIN32_FIND_DATAW findData;
HANDLE hFind = INVALID_HANDLE_VALUE;
wchar_t searchPath[MAX_PATH];
_snwprintf(searchPath, MAX_PATH, L"%s\\*", path);
hFind = FindFirstFileW(searchPath, &findData);
if (hFind == INVALID_HANDLE_VALUE) {
std::cout << "Failed to find first file!\n";
return -1;
}
do {
if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
std::wcout << L"File Name: " << findData.cFileName << '\n';
}
} while (FindNextFileW(hFind, &findData) != 0);
FindClose(hFind);
return 0;
}
|
这个示例代码使用了 Unicode 版本的 WIN32_FIND_DATAW
、FindFirstFileW
和 FindNextFileW
函数来处理 Unicode 字符串。
需要注意的是,之所以要使用 _snwprintf
函数而不是 snwprintf
函数,是因为后者可能不受某些平台的支持。函数参数中的 L
前缀表示字符串和字符都是 Unicode 格式的,因此需要将 LPCSTR
改为 LPCWSTR
。
读文件
可以使用 C++ 的 fstream
库中的 getline
函数实现从文件中读取字符串,每次读取一行。以下是示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include <iostream>
#include <fstream>
#include <string>
int main() {
std::ifstream file("example.txt"); // 打开文件 example.txt
if (!file.is_open()) {
std::cout << "Failed to open file.\n";
return 1;
}
std::string line;
while (std::getline(file, line)) { // 逐行读取文件
std::cout << line << "\n"; // 输出每行内容
}
file.close(); // 关闭文件
return 0;
}
|
在这个示例代码中,我们首先通过 ifstream
对象打开了名为 example.txt
的文件,并检查是否成功打开。然后,我们在一个循环中使用 getline
函数来逐行读取文件内容,将每行字符串存储在 line
变量中,并将其输出到控制台上。最后,我们关闭了文件。
您可以使用 C++ 的 fstream
库中的 ifstream
类来从文件中每次读取指定字节长度的数据。以下是示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include <iostream>
#include <fstream>
int main() {
std::ifstream file("example.bin", std::ios::binary); // 打开 binary 文件
if (!file.is_open()) {
std::cout << "Failed to open file.\n";
return 1;
}
const int bufSize = 4; // 每次读取 4 个字节
char buffer[bufSize] = {0}; // 缓冲区
while (file.read(buffer, bufSize)) { // 从文件中读取数据,直到文件末尾
std::cout << "Read " << file.gcount() << " bytes: "; // 输出已读取的字节数
for (int i = 0; i < bufSize; ++i) {
std::cout << (int)(unsigned char)buffer[i] << " "; // 输出每个字节的值
}
std::cout << std::endl;
}
file.close();
return 0;
}
|
在这个示例代码中,我们使用 ifstream
对象打开了名为 example.bin
的二进制文件,并指定了 std::ios::binary
参数,表示以字节流的方式打开文件。然后,我们定义了一个缓冲区 buffer
,每次从文件中读取 4 个字节数据,并输出已读取的字节数及每个字节的值。最后,我们关闭了文件。
写文件
您可以使用 C++ 的 fstream
库中的 ofstream
类来实现写一个文件。以下是示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include <iostream>
#include <fstream>
int main() {
std::ofstream file("example.txt"); // 创建文件 example.txt
if (!file.is_open()) {
std::cout << "Failed to create file.\n";
return 1;
}
file << "Hello, world!\n"; // 写入字符串到文件中
file << "This is an example.\n";
file.close();
return 0;
}
|
在这个示例代码中,我们使用 ofstream
对象创建了名为 example.txt
的文件,并检查是否成功创建。然后,我们将两个字符串写入文件中,每个字符串占一行。最后,我们关闭了文件。
可以使用 C++ 的 fstream
库中的 ofstream
类来以字节流的方式写一个文件。以下是示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include <iostream>
#include <fstream>
int main() {
std::ofstream file("example.bin", std::ios::binary); // 创建二进制文件 example.bin
if (!file.is_open()) {
std::cout << "Failed to create file.\n";
return 1;
}
char data[4] = { 0x01, 0x02, 0x03, 0x04 }; // 4 字节数据
file.write(data, sizeof(data)); // 写入数据到文件中
file.close();
return 0;
}
|
在这个示例代码中,我们使用 ofstream
对象创建了名为 example.bin
的二进制文件,并指定了 std::ios::binary
参数,表示以字节流的方式打开文件。然后,我们定义了一个包含 4 个字节的数据数组 data
,将其写入文件中。最后,我们关闭了文件。
计算一个文件的大小
可以使用C++11标准库中的fstream头文件来计算文件的大小,具体操作如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#include <iostream>
#include <fstream>
int main() {
std::ifstream file("example.txt", std::ios::binary | std::ios::ate);
std::streamsize size = file.tellg(); // 获取文件指针当前位置,即文件大小
file.close();
if (size == -1) {
std::cout << "无法计算文件大小" << std::endl;
} else {
std::cout << "文件大小为 " << size << " 字节" << std::endl;
}
return 0;
}
|
这段代码中,我们首先使用std::ifstream类来打开一个二进制文件,并将文件指针定位到文件末尾,然后使用tellg()函数获取文件指针当前位置,即文件大小,最后关闭文件。如果无法计算文件大小,则tellg()函数会返回-1。
需要注意的是,std::ios::binary
标志是可选的,但建议使用,因为在某些平台上,二进制文件和文本文件的行结束符可能不同,而这个标志可以确保以二进制模式打开文件。
std::ios::ate
是C++标准库中std::ios
类的一个标志,它表示在打开文件时将文件指针移动到文件的末尾,这样我们就可以使用tellg()
函数获取文件大小。
具体来说,std::ios::ate
是std::ios
类中的一个打开模式标志,表示将文件指针初始位置设置为文件末尾,也就是说,在打开文件时,文件指针会自动移动到文件的末尾。这个标志通常与std::ios::binary
一起使用,以确保以二进制模式打开文件并且获取的文件大小是以字节为单位的。
如果没有使用std::ios::ate
标志,则文件指针初始位置将是文件的开头,这样我们就需要手动将指针移动到文件的末尾才能获取文件大小,这样的代码通常比较繁琐,使用std::ios::ate
可以简化这个过程。
设置文件的偏移位置
方式1(推荐)
要设置std::ifstream
对象中文件的偏移位置,可以使用seekg
成员函数。此函数用于设置文件的读取位置。
以下是使用seekg
函数设置文件偏移位置的示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include <fstream>
#include <iostream>
int main() {
std::ifstream infile("example.txt");
if (!infile) {
std::cerr << "Failed to open file." << std::endl;
return 1;
}
// 将读取位置设置为文件的第100个字节处
infile.seekg(100, std::ios::beg);
// 从文件的当前位置读取一个字符
char c;
infile.get(c);
std::cout << "Character at offset 100: " << c << std::endl;
infile.close();
return 0;
}
|
在上面的代码中,std::ifstream
对象用于打开名为example.txt
的文件。如果文件无法打开,则会打印一条错误消息并返回。然后,使用seekg
函数将读取位置设置为文件的第100个字节处。第一个参数表示偏移量,第二个参数指定了偏移位置的参考点。在这个例子中,使用std::ios::beg
表示从文件的开头开始计算偏移量。
最后,使用get
函数从文件的当前位置读取一个字符,并使用std::cout
函数打印该字符。同样,当您完成文件操作后,一定要使用close
函数关闭文件。
方式2
要设置文件的偏移位置,可以使用std::fseek
函数。此函数在C++ 11标准中仍然可用。
以下是使用std::fseek
函数设置文件偏移量的示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#include <cstdio>
int main() {
FILE* file = std::fopen("example.txt", "r");
if (file == nullptr) {
std::perror("Failed to open file");
return 1;
}
// 移动文件指针到文件的第 100 个字节处
std::fseek(file, 100, SEEK_SET);
// 读取文件指针当前位置的字符
char c = std::fgetc(file);
std::printf("Character at offset 100: %c\n", c);
std::fclose(file);
return 0;
}
|
在上面的代码中,std::fopen
函数用于打开一个名为example.txt
的文件,并返回一个指向该文件的指针。如果文件无法打开,则会打印一条错误消息并返回。
std::fseek
函数用于将文件指针移动到文件的第100个字节处。第二个参数指定要移动的字节数,第三个参数指定了移动的参考位置,这里使用SEEK_SET
表示从文件的开头开始计算偏移量。
最后,使用std::fgetc
函数读取文件指针当前位置的字符,并使用std::printf
函数打印该字符。
当您完成文件操作后,一定要使用std::fclose
函数关闭文件。这是一种非常重要的好习惯,因为这可以确保在程序退出之前将所有缓冲区数据写入磁盘。
文件操作
实现一个以某个字符分割字符串的功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
#include <iostream>
#include <string>
#include <vector>
using namespace std;
// 定义切割函数
vector<string> split(string str, char delimiter) {
vector<string> result; // 存放结果的向量
string token = ""; // 存放当前截取的子串
// 遍历源字符串,如果当前字符不是分隔符就添加到token中
for (int i = 0; i < str.length(); i++) {
if (str[i] != delimiter) {
token += str[i];
}
// 如果当前字符是分隔符或已经遍历到了源字符串末尾
if (str[i] == delimiter || i == str.length() - 1) {
result.push_back(token); // 将当前token添加到结果向量
token = ""; // 清空token,准备截取下一个子串
}
}
return result;
}
int main() {
string str = "\t\t12\t34\t\t";
vector<string> result = split(str, '\t');
for (int i = 0; i < result.size(); i++) {
cout << "\"" << result[i] << "\"" << ",";
}
return 0;
}
|
在这个例子中,我们定义了一个split函数来实现字符串的分割功能。该函数使用了一个for循环来遍历源字符串中的每一个字符,并判断其是否为分隔符。如果当前字符不是分隔符,则将其添加到当前token中;如果当前字符是分隔符或已经遍历到了源字符串末尾,则将当前token添加到结果向量中,并清空token,准备截取下一个子串。最终,该函数返回结果向量。
在main函数中,我们使用split函数来分割字符串"\t\t12\t34\t\t"
,以'\t'
作为分隔符。并将得到的结果向量输出到控制台上,用引号括起每个子串,方便查看结果。
需要注意的是以’-‘进行分割:"-2017" => {"", 2017}