更換電腦機殼風扇 Cooler Master

最近發現電腦的風扇出現異常大聲,經過幾次的交叉測試最後發現不是CPU風扇(鬆一口氣),
原來兇手是機殼的後風扇,風扇拔下來後發現風扇直立運算時不會有噪音,
但橫擺運轉會有噪音+振動,看來已經用很久了該換了!
我的機殼是使用 Lancool PC-K07 (Lian Li 的子品牌),
機殼上的後風扇大小是 12x12 cm,型號是 LI121225SE-4,DC 12V,0.08A,12123cm

最後在原價屋買了 Cooler Master 12公分長效 Rifle 風扇,型號是 AL025-18R2-3AN,花了我 $120 塊,把它換上後終於沒異音了。

Cooler Master 風扇正面

Cooler Master 風扇背面

拆封後

Python max 用法與範例

本篇 ShengYu 介紹 Python max 用法與範例,Python max 函式是用來求兩數最大值,Python max 函式也可以拿來計算 list 的最大值,

Python max 求兩數最大值

Python 內建就有提供 max() 函式可以使用,免去重新自己寫一個 max 函式的時間,以下為 Python max 兩數求最大值的方法,

python3-max-1.py
1
2
3
4
5
6
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

print(max(4, 6))
print(max(11, 7))
print(max(16.6, 18.1))

Python max 輸出結果如下,

1
2
3
6
11
18.1

Python max 函式求 list 最大值

Python max 也可以求 list 的最大值,方法如下,

python3-max-2.py
1
2
3
4
5
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

mylist = [5,3,-5,6,2,4]
print(max(mylist))

Python max 輸出結果如下,

1
6

以上就是 Python max 用法與範例的介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它相關文章推薦
Python 新手入門教學懶人包

C/C++ const 的 3 種用法與範例

本篇 ShengYu 介紹 C/C++ const 的 3 種用法與範例,包含 C++ const 平常的一般基本用法以及 C++ const 在成員函式中的用法。

以下 C/C++ const 的用法介紹分別為這幾種,

  • C/C++ const 加上變數前的用法
  • C++ const 加在成員函式前面的用法
  • C++ const 加在成員函式後面的用法

那我們開始吧!

C/C++ const 加上變數前的用法

這邊介紹 C/C++ const 加上變數前的用法,C/C++ const 加上變數前表示不能修改該變數,該變數為 read-only,

如下範例所示,宣告 const int n = 5; 之後如果嘗試對 n 進行修改的話會得到 error: assignment of read-only variable ‘n’ 編譯錯誤訊息,

1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;

int main() {
const int n = 5;
//n = 10; // compile error
return 0;
}

這邊要另外舉個字串指標的例子,const char *str 雖然是不能修改其 str 指標指向的內容,但 str 指標本身卻是可以修改的,所以這部份在使用上需要特別注意,詳細說明如下,

如下例所示,宣告一個 const char * name2 = "Amy";,name2 表示指標指向的內容不可修改,如果嘗試對 name2 指標指向的內容進行修改的話會得到 error: assignment of read-only location ‘* name2’ 編譯錯誤,例如下例中的 name2[0] = 'B'; 就是對 name2 指向的內容進行修改,

但是 name2 指標本身是可以修改的,也就是可以修改 name2 指標指向別的地方,如下例中的 name2 = name; 將 name2 指向 name,這樣 name2 印出來的內容就會是 Tom 而不是 Amy,

如果要指標本身不可修改的話,可以像下中的 name3 前加上 const 變成 const char * const name3,這樣就是表示指標本身不可修改且指向的內容也不可修改,之後如果嘗試對 name3 的指標進行修改的話會得到 error: assignment of read-only variable ‘name3’ 編譯錯誤訊息,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <string>
using namespace std;

int main() {
char name[5] = "Tom";
cout << name << "\n";

const char * name2 = "Amy";
//name2[0] = 'B'; // compile error, 不可修改 name2 指向的內容
name2 = name; // 可以修改 name2 指標
cout << name2 << "\n";

const char * const name3 = "Amy";
//name3 = name; // compile error, 不可修改 name3 指標本身

return 0;
}

結果輸出如下,

1
2
Tom
Tom

如果換成整數指標的話就可能有這幾種情況,

1
2
3
4
const int * a = &b; // 指標指向的內容不可改變
int const * a = &b; // 同上
int * const a = &b; // 常數指標,即指標本身的值是不可改變的,但指向的內容是可改變的
const int * const a = &b; // 指向常數的常數指標,即指標本身與指向的內容都是不可改變的

綜合上述指標加上 const 的用法大致分成兩種情況,一種就是不可修改的指標,另一種則是指標指向的內容(記憶體區塊)不可修改,
不可修改的指標:即指標不可修改,代表該指標永遠指向某塊記憶體位置
指標指向的內容(記憶體區塊)不可修改:即指標指向的記憶體區塊不能修改,只能讀取 read-only

C++ const 加在成員函式前面的用法

在 C++ 中有時候希望回傳的東西不能被修改的話,這時就可以使用 const 加在成員函式前面來達成這個目的,我們來看看下面這個例子,

在 main 函式裡要取得 s.getName() 成員函式回傳的變數話需要宣告一個 const std::string& studentName,由於 studentName 是 const 的關係所以之後我們就只能對這個變數作讀取不能修改值,如果嘗試對 studentName 進行修改的話會得到編譯錯誤,

因為 studentName 是 reference 參考的關係,所以之後使用 s.setName("Tom") 改變了 s 物件裡的 name 後,之後 studentName 裡面的值也會跟著改變,

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
#include <iostream>
#include <string>

class Student {
public:
Student() {}

const std::string& getName() {
return name;
}

void setName(std::string name) {
this->name = name;
}

private:
std::string name = "unknown";
};

int main() {
Student s;
const std::string& studentName = s.getName();
std::cout << studentName << "\n";
// studentName = "Tom"; compile error
s.setName("Tom");
std::cout << studentName << "\n";
return 0;
}

結果輸出如下,

1
2
unknown
Tom

再舉個 STL 容器的例子,使用 std::queue 容器 將 1、2、3 元素推入後,之後使用 front() 取得頭部元素,這時我們只是需要把變數 n 印出來而已,所以不會對它進行修改,如果嘗試對 const int &n 修改的話會得到編譯錯誤的 error: cannot assign to variable 'n' with const-qualified type 'const int &' 訊息,

另外宣告 int &n2 = q.front(); 參考的方式來修改 queue 頭部元素,之後 n 裡面的數值也會跟著改變,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <queue>

int main() {
std::queue<int> q;
q.push(1);
q.push(2);
q.push(3);
const int &n = q.front();
// n = 5; compile error
std::cout << n << "\n";

int &n2 = q.front();
n2 = 4;
std::cout << n << "\n";
return 0;
}

輸出結果如下,

1
2
1
4

C++ const 加在成員函式後面的用法

這邊介紹 C++ const 加在成員函式後面的用法,const 加在成員函式後面表示不能在該成員函式裡修改類別成員變數,因為該函式裡的存取類別成員都會是 read-only,範例如下,

如果在 getCounter() 成員函式裡嘗試對 counter 進行修改會得到編譯錯誤(error: increment of member ‘Object::counter’ in read-only object),對其它類別成員 number 修改也是會得到編譯錯誤(error: assignment of member ‘Object::number’ in read-only object),但是對 getCounter() 裡宣告的 number2 區域變數可以進行修改,

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
35
#include <iostream>
using namespace std;

class Object {
public:
Object() {}

int getCounter() const {
//counter++; // compile error, const 加在成員函式後面表示不行在該函式裡修改成員變數
//number = 10; // compile error, const 加在成員函式後面表示不行在該函式裡修改成員變數
int number2;
number2 = 10; // 區域變數可以進行修改
return counter;
}

void addCount() {
counter++;
}

private:
int counter = 0;
int number = 0;
};

int main() {
Object o;
int counter = o.getCounter();
std::cout << counter << "\n";
o.addCount();
std::cout << counter << "\n";

int counter2 = o.getCounter();
std::cout << counter2 << "\n";
return 0;
}

以上就是 C/C++ const 的 3 種用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它參考
https://welkinchen.pixnet.net/blog/post/48176548
https://docs.microsoft.com/zh-tw/cpp/cpp/const-cpp?view=msvc-170
https://blog.xuite.net/coolflame/code/16605512

其它相關文章推薦
如果你想學習 C++ 相關技術,可以參考看看下面的文章,
C/C++ 新手入門教學懶人包
C/C++ static 的 5 種用法
C/C++ extern 用法與範例
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別

C/C++ extern 用法與範例

本篇 ShengYu 介紹 C/C++ extern 用法與範例。

以下 C/C++ extern 的用法與範例分為這幾部分介紹,

  • C/C++ extern 引用外部變數
  • C/C++ extern 引用外部函式

那我們開始吧!

C/C++ extern 引用外部變數

這邊介紹 C/C++ extern 引用外部變數的使用方式,這邊指的是 extern 引用外部的全域變數,這個方法使用的前提是該變數不能為 static,static 的用法之前有介紹過,假設我有 main.cpp、a.h、a.cpp、b.h、b.cpp 這幾隻檔案,在 main 函式裡呼叫 bbb 函式,bbb 函式位於 b.cpp 裡,但 bbb 函式會使用到 a.cpp 裡的全域變數 counter 的話要怎麼使用呢?

這邊 ShengYu 舉個簡單的範例,在 main.cpp 很簡單的呼叫 aaa() 函式以後,再呼叫 bbb() 函式,接下來看看這流程,

main.cpp
1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include "a.h"
#include "b.h"

int main() {
aaa();
printf("%d\n", bbb(5));
return 0;
}

a.h 內容如下,很簡單的只有 aaa 函式原型宣告,

a.h
1
void aaa();

a.cpp 內容如下,counter 變數宣告是在 a.cpp 裡的全域變數,呼叫 aaa 函式則會增加 counter,注意的是這邊 counter 如果宣告成 static 則其它 *.cpp 則無法引用,這用途相似於 class 裡的 private 變數的概念,

a.cpp
1
2
3
4
5
int counter = 0;

void aaa() {
counter++;
}

b.h 內容如下,很簡單的只有 bbb 函式原型宣告,

b.h
1
int bbb(int x);

b.cpp 內容如下,使用 extern 來標記/引用 counter 這個全域變數,所以這邊 b.cpp 實際上不會產生一個 counter 變數的實體,在編譯連結時期會引用 a.o 的 counter,

b.cpp
1
2
3
4
5
extern int counter;

int bbb(int x) {
return x + counter;
}

使用以下 g++ 指令進行編譯與連結,順序為將 a.cpp 編譯成 a.o 中繼檔,將 b.cpp 編譯成 b.o 中繼檔,將 main.cpp 編譯成 main.o 中繼檔,最後將這些中檔連結起來輸出成 a.out 執行檔,

1
2
3
4
g++ -c a.cpp
g++ -c b.cpp
g++ -c main.cpp
g++ -o a.out main.o a.o b.o

執行 a.out 的結果輸出如下,

1
6

由上面的實驗可以了解 C/C++ extern 的用法與用途,那反過來想如果今天我的全域變數不想給別人 extern 時就可以加上 static。
延伸閱讀:C/C++ static 的 5 種用法

C/C++ extern 引用外部函式

既然 extern 有引用外部變數的方式,那麼有沒有 extern 引用外部函式呢?

結果是有的!C/C++ extern 引用外部函式跟引用外部變數用法差不多,這邊就簡單介紹一下,基本上要 extern 的函式前提是該函式不能為 static,這點跟 extern 外部變數一樣,函式前面加上 static 的用意就是希望它只能在這支原始檔裡使用,不想給別人呼叫,有點像 class 裡的 private function 的味道,所以要 extern 函式要先確定一下這件事,否則會編譯失敗,

這邊就簡單舉例一下,跟前述例子差不多,只是這次沒有 a.h 跟 b.h,而且 a.cpp 新增了 print_counter 函式來印出 counter,以下是 a.cpp 內容,

a.cpp
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int counter = 0;

static void print_counter(int c) {
printf("counter: %d\n", c);
}

void aaa() {
counter++;
print_counter(counter);
}

b.cpp 內容如下,跟前述例子一樣,

b.cpp
1
2
3
4
5
extern int counter;

int bbb(int x) {
return x + counter;
}

main.cpp 內容如下,可以看到在 main.cpp 裡可以使用 extern 引用 aaa 與 bbb 函式,extern 引用函式後就可以順利使用,編譯跟執行是沒有問題的!但是如果要 extern print_counter 函式的話編譯時就會連結錯誤,

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

extern void aaa();
extern int bbb(int x);
//extern void print_counter(int c); // 連結錯誤, 因為 print_counter 是 static

int main() {
aaa();
printf("%d\n", bbb(5));
//print_counter(10); // 連結錯誤, 因為 print_counter 是 static
return 0;
}

編譯的指令如下,跟前述例子一樣,

1
2
3
4
g++ -c a.cpp
g++ -c b.cpp
g++ -c main.cpp
g++ -o a.out main.o a.o b.o

執行 a.out 的結果輸出如下,

1
2
counter: 1
6

如果嘗試在 main.cpp extern print_counter 並呼叫 print_counter 函式的話,編譯時會連結錯誤,錯誤訊息如下,

1
2
3
main.o: In function `main':
main.cpp:(.text+0x2a): undefined reference to `print_counter(int)'
collect2: error: ld returned 1 exit status

延伸閱讀:C/C++ static 的 5 種用法

C/C++ extern 還有另一種用法是 extern "C",下次有機會再給大家介紹。
以上就是 C/C++ extern 用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它參考
https://medium.com/@alan81920/c-c-%E4%B8%AD%E7%9A%84-static-extern-%E7%9A%84%E8%AE%8A%E6%95%B8-9b42d000688f
https://docs.microsoft.com/zh-tw/cpp/cpp/extern-cpp?view=msvc-170
https://mitblog.pixnet.net/blog/post/37137361

其它相關文章推薦
如果你想學習 C++ 相關技術,可以參考看看下面的文章,
C/C++ 新手入門教學懶人包
C/C++ static 的 5 種用法

Python 寫入二進制檔

本篇介紹 Python 寫入二進制檔的方法,

以下 Python 寫入 binary 檔的方法將分為這幾部份,

  • Python 寫入二進制檔的基本用法
  • Python 使用 struct.pack() 寫入 str 字串到二進制檔
  • Python 使用 struct.pack() 寫入 int 整數到二進制檔
  • Python 使用 struct.pack() 寫入多種資料到二進制檔

Python 寫入二進制檔的基本用法

這邊介紹 Python 寫入二進制檔的基本用法,Python 寫二進制檔時 open() 開檔要使用 'wb',這邊示範寫入一個 hello 字串到二進制檔裡,write() 只接受 bytes 類別不接收 str 類別,所以需要將字串先轉成 bytes,

1
2
3
4
5
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

with open('xxx.bin', 'wb') as f:
f.write(b'hello')

Ubuntu 下看二進制檔的 hex 的話可以使用 dhex 工具,使用 sudo apt install dhex 安裝即可使用,dhex 使用畫面如下圖所示,

Python 使用 struct.pack() 寫入 str 字串到二進制檔

這邊介紹 Python 使用 struct.pack() 寫入 str 到二進制檔,Python 只提供 read 與 write 函式寫入,並沒有提供對二進制讀取與寫入的函式,但是可以透過 struct 模組來達成這件事,這邊使用 struct.pack() 將資料打包成 bytes 物件的形式然後透過 write() 寫入二進制檔,例如將 hello world 寫到二進制檔裡,

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import struct

s = b'hello world'
bytes_str = struct.pack('11s', s)
print(type(bytes_str))
print(bytes_str)
with open('xxx.bin', 'wb') as f:
f.write(bytes_str)

如果要讀取的話可以看這篇

Python 使用 struct.pack() 寫入 int 整數到二進制檔

這邊介紹 Python 使用 struct.pack() 寫入 int 到二進制檔,例如將 123 寫到二進制檔裡,

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import struct

num = 123
bytes_str = struct.pack('i', num)
print(type(bytes_str))
print(bytes_str)
with open('xxx.bin', 'wb') as f:
f.write(bytes_str)

結果輸出如下,

1
2
<class 'bytes'>
b'{\x00\x00\x00'

如果要讀取的話可以看這篇

Python 使用 struct.pack() 寫入多種資料到二進制檔

這邊介紹 Python 使用 struct.pack() 寫入多種資料到二進制檔,如果我們要 Python 使用 struct.pack() 寫入多種資料型態的話,可以這樣寫,假設我要寫入一個整數 123、一個浮點數 45.67,一個短整數 89,

1
struct.pack('ifh', 123, 45.67, 89)

那麼將這些多種類型資料利用 struct.pack() 寫入二進制,就會是像這樣寫,

1
2
3
4
5
6
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import struct

with open('xxx.bin', 'wb') as f:
f.write(struct.pack('ifh', 123, 45.67, 89))

剛剛是數字混合類型的範例,這次我們加入字串會是怎樣寫呢?
假設我要寫入一個字串 hello、一個整數 12、一個浮點數 34.56、一個字串 python

1
struct.pack('5sif6s', 'hello', 12, 34.56, 'python')

那麼將這些多種類型資料利用 struct.pack() 寫入二進制,就會像下範例這樣寫,

1
2
3
4
5
6
7
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import struct

bytes_str = struct.pack('5sif6s', b'hello', 12, 34.56, b'python')
with open('xxx.bin', 'wb') as f:
f.write(bytes_str)

如果要讀取的話可以看這篇

以上就是 Python 寫入二進制檔介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其他參考
Python how to write to a binary file? - Stack Overflow
https://stackoverflow.com/questions/18367007/python-how-to-write-to-a-binary-file

其它相關文章推薦
Python 新手入門教學懶人包

Python 讀取二進制檔

本篇介紹 Python 讀取二進制檔的方法,

以下 Python 讀取 binary 檔的方法將分為這幾部份,

  • Python 讀取二進制檔的基本用法
  • Python 使用 struct.unpack() 讀取二進制檔的 str 字串
  • Python 使用 struct.unpack() 讀取二進制檔的 int 整數
  • Python 使用 struct.unpack() 讀取二進制檔的多種資料

Python 讀取二進制檔的基本用法

在 Python 3 讀取二進制的範例如下,讀二進制檔時 open() 開檔模式要使用 'rb',跟 Python 2 不同的是 Python 3 讀進來的是 bytes 類別,而 Python 2 讀進來的是字元,以下示範Python 讀取 binary 檔的寫法,假設這個 binary 檔叫做 xxx.bin,binary 檔案名稱你可以取任何名字,但通常我們不使用 .txt 作為副檔名,以免混淆,

python3-bin-read.py
1
2
3
4
5
6
7
8
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

with open('xxx.bin', 'rb') as f:
data = f.read()

print(type(data))
print(data)

讀取一個內容為 hello 的二進制檔的結果如下,

1
2
<class 'bytes'>
b'hello'

怎麼寫入可以看這篇

我們可以將上述範例改寫成用十六進制方式印出來,

python3-bin-read2.py
1
2
3
4
5
6
7
8
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

with open('xxx.bin', 'rb') as f:
data = f.read()

for i in range(len(data)):
print(hex(data[i]) + ' ', end='')

讀取一個內容為 hello 的二進制檔的結果如下,

1
0x68 0x65 0x6c 0x6c 0x6f

Python 使用 struct.unpack() 讀取二進制檔的 str 字串

這邊介紹 Python 使用 struct.unpack() 讀取二進制檔的 str 字串,Python 只提供 read 與 write 函式寫入,並沒有提供對二進制讀取與寫入的函式,但是可以透過 struct 模組來達成這件事,以下範例是從二進制檔讀取長度 11 的字串,要注意的是 struct.unpack() 回傳的變數類型是 tuple,

python-bin-read3.py
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import struct

with open('xxx.bin', 'rb') as f:
data = f.read()
b, = struct.unpack('11s', data)
print(type(b))
print(b)
print(b.decode())

讀取一個內容為 hello world 的二進制檔的結果如下,

1
2
3
<class 'bytes'>
b'hello world'
hello world

因為 struct.unpack() 回傳的變數類型是 tuple,所以回傳變數只有一個的話需要這樣寫,

1
2
3
(b,) = struct.unpack('11s', f.read())
# or
b, = struct.unpack('11s', f.read())

struct.unpack() 回傳多個變數的用法的話可以這樣寫,

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import struct

with open('xxx.bin', 'rb') as f:
data = f.read()
b1,b2 = struct.unpack('5s6s', data)

print(b1.decode())
print(b2.decode())

結果輸出如下,

1
2
hello
world

Python 使用 struct.unpack() 讀取二進制檔的 int 整數

這邊介紹 Python 使用 struct.unpack() 讀取二進制檔的 int 整數,從二進制檔裡讀取 int,要注意的是 struct.unpack() 回傳的變數類型是 tuple,

1
2
3
4
5
6
7
8
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import struct

with open('xxx.bin', 'rb') as f:
data = f.read()
(num,) = struct.unpack('i', data)
print(num)

讀取一個內容為 123 的二進制檔的結果如下,

1
123

因為 struct.unpack() 回傳的變數類型是 tuple,所以回傳變數只有一個的話需要這樣寫,

1
2
3
(num,) = struct.unpack('i', f.read())
# or
num, = struct.unpack('i', f.read())

怎麼寫入可以看這篇

Python 使用 struct.unpack() 讀取二進制檔的多種資料

這邊介紹 Python 使用 struct.unpack() 讀取二進制檔的多種資料,如果我們要 Python 使用 struct.unpack() 讀取多種資料型態的話,可以這樣寫,假設我要讀取一個整數 123、一個浮點數 45.67,一個短整數 89,

1
(a,b,c) = struct.unpack('ifh', f.read())

那麼將這些多種類型資料利用 struct.unpack() 從二進制檔讀取,就會是像這樣寫,

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import struct

with open('xxx.bin', 'rb') as f:
(a,b,c) = struct.unpack('ifh', f.read())
print(a)
print(b)
print(c)

結果輸出如下,

1
2
3
123
45.66999816894531
89

剛剛是數字混合類型的範例,這次我們加入字串會是怎樣寫呢?
假設我要讀取一個字串 hello、一個整數 12、一個浮點數 34.56、一個字串 python

1
(a,b,c,d) = struct.unpack('5sif6s', f.read())

那麼將這些多種類型資料利用 struct.unpack() 從二進制檔讀取,就會像下範例這樣寫,

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import struct

with open('xxx.bin', 'rb') as f:
(a,b,c,d) = struct.unpack('5sif6s', f.read())
print(a)
# print(a.decode('utf-8'))
print(b)
print(c)
print(d)
# print(d.decode('utf-8'))

結果輸出如下,要將 bytes 轉換成字串的話可以用 decode()

1
2
3
4
b'hello'
12
34.560001373291016
b'python'

怎麼寫入可以看這篇

以上就是 Python 讀取二進制檔介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其他參考
python - Reading binary file and looping over each byte - Stack Overflow
https://stackoverflow.com/questions/1035340/reading-binary-file-and-looping-over-each-byte
https://www.delftstack.com/zh-tw/howto/python/read-binary-files-in-python/

其它相關文章推薦
Python 新手入門教學懶人包

Python bytes 轉 string 的 2 種方法

本篇 ShengYu 介紹 Python bytes 轉 string 的 2 種方法,

以下 Python bytes 轉字串的方法將分為這幾種,

  • Python str 類別建構子
  • Python bytes.decode() 成員函式

那我們開始吧!

Python str 類別建構子

Python 3 可以使用 str 類別的建構子來轉換 bytes,在 str 類別的建構子中帶入 bytes 就會將 bytes 轉成 字串,預設編碼為 None,需要指定編碼否則不會轉換出正確的字串,

1
2
3
4
5
6
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

b = b'hello'
print(str(b, encoding='utf-8'))
print(type(str(b, encoding='utf-8')))

結果輸出如下,

1
2
hello
<class 'str'>

Python bytes.decode() 成員函式

Python 3 使用 bytes.decode() 成員函式也可以將該 bytes 轉成字串,decode() 預設編碼就是 'utf-8',有其它需求也可以指定其它編碼,

1
2
3
4
5
6
7
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

b = b'hello'
print(b.decode())
print(type(b.decode()))
print(b.decode(encoding='utf-8'))

結果輸出如下,

1
2
3
hello
<class 'str'>
hello

以上就是 Python bytes 轉 string 的 2 種方法介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它相關文章推薦
Python 新手入門教學懶人包

Python 判斷 OS 作業系統的 3 種方法

本篇 ShengYu 介紹 Python 判斷 OS 作業系統的 3 種方法,以下的 Python 判斷 OS 作業系統的方法將分為這幾部分,

  • Python os.name
  • Python sys.platform
  • Python platform.system()

那我們開始吧!

Python os.name

Python 判斷 OS 作業系統的方法可以使用 os.name,這邊以 Python 3 為例,os.name 會回傳 posixntjava 這幾種結果,使用前要先 import os

1
2
3
4
5
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os

print(os.name)

Ubuntu 16.04 的輸出如下,

1
posix

MacOS 10.15.7 的輸出如下,

1
posix

Windows 10 的輸出如下,

1
nt

在 os 模組下還有另一個 uname() 函式可以使用,uname() 會回傳作業系統相關的版本資訊,

1
2
3
4
5
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os

print(os.uname())

Ubuntu 16.04 的輸出如下,

1
posix.uname_result(sysname='Linux', nodename='shengyu', release='4.10.0-40-generic', version='#44~16.04.1-Ubuntu SMP Thu Nov 9 15:37:44 UTC 2017', machine='x86_64')

MacOS 10.15.7 的輸出如下,

1
posix.uname_result(sysname='Darwin', nodename='shengyudeMacBook-Pro.local', release='19.6.0', version='Darwin Kernel Version 19.6.0: Thu Sep 16 20:58:47 PDT 2021; root:xnu-6153.141.40.1~1/RELEASE_X86_64', machine='x86_64')

Windows 下沒有 os.uname()

sys.platform 有更細的分類,下一節會介紹。

Python sys.platform

Python 判斷 OS 作業系統的方法可以使用 sys.platform,sys.platform 回傳的結果有 aixlinuxwin32cygwindarwin 這幾種,

1
2
3
4
5
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys

print(sys.platform)

Ubuntu 16.04 的輸出如下,

1
linux

MacOS 10.15.7 的輸出如下,

1
darwin

Windows 10 的輸出如下,

1
win32

sys.platform 回傳的種類情況分為這幾種,

系統種類 回傳值
AIX 'aix'
Linux 'linux'
Windows 'win32'
Windows/Cygwin 'cygwin'
macOS 'darwin'

Python 如果要用 sys.platform 判斷 OS 作業系統的話可以使用 startswith(),像 linux 與 linux2 的情況就可以被包含在以 linux 開頭的字串,寫在同一個條件式裡,

python3-detect-os.py
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys

if sys.platform.startswith('linux'): # 包含 linux 與 linux2 的情況
print('Linux')
elif sys.platform.startswith('darwin'):
print('macOS')
elif sys.platform.startswith('win32'):
print('Windows')

Python platform.system()

Python 判斷 OS 作業系統的方法可以使用 platform.system() 函式,platform.system() 會回傳作業系統的名稱,例如:LinuxDarwinJavaWindows 這幾種,如果無法判別作業系統的話會回傳空字串,

1
2
3
4
5
6
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import platform

print(platform.system())
print(platform.release())

Ubuntu 16.04 的輸出如下,

1
2
Linux
4.10.0-40-generic

MacOS 10.15.7 的輸出如下,

1
2
Darwin
19.6.0

Windows 10 的輸出如下,

1
2
Windows
10

以上就是 Python 判斷 OS 作業系統的介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它參考
When to use os.name, sys.platform, or platform.system?
https://stackoverflow.com/questions/4553129/when-to-use-os-name-sys-platform-or-platform-system
cross platform - Python: What OS am I running on? - Stack Overflow
https://stackoverflow.com/questions/1854/python-what-os-am-i-running-on

其它相關文章推薦
Python 新手入門教學懶人包

Python open with 用法與範例

本篇 ShengYu 介紹 Python open with 用法與範例,

以下 Python open with 用法與範例將分為這幾部份,

  • Python open with 開檔讀取文字檔
  • Python open with 指定讀取檔案的編碼格式
  • Python open with 開檔寫入文字檔
  • Python open with 開檔讀取二進制檔
  • Python open with 開檔寫入二進制檔

那我們開始吧!

Python open with 開檔讀取文字檔

Python 要讀取一個文字檔會先用 open 來開檔,在 open() 函式裡的第一個引數放入檔案路徑名稱,第二個引數為開檔模式,有讀檔模式、寫入模式或讀寫模式等等,讀檔模式就用 'r',像這樣寫,

1
2
3
4
5
6
7
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

f = open('xxx.txt', 'r')
text = f.read()
print(text)
f.close()

如果開檔有問題,例如要開啟的檔案不存在,open() 函式就會拋出一個 IOError 的錯誤,並且給出錯誤碼和詳細的資訊告訴你檔案不存在,

1
2
3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: 'xxx.txt'

如果開檔成功的話,那麼接下來可以使用 read() 一次讀取該檔案的全部內容,或者使用 readlines() 搭配迴圈一次讀取一行文字,最後當檔案使用完畢時需要使用 close() 函式來關閉檔案,在檔案的開檔與讀取過程中都有可能會產生 IOError 例外錯誤,一旦出現例外錯誤,後面的 f.close() 函式就執行不到了,所以為了保證無論過程中有無出錯都要能正確地關閉檔案,我們可以使用 try… finially 來達成,像下述範例這樣寫,

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

try:
f = open('xxx.txt', 'r')
text = f.read()
print(text)
except:
print('error')
finally:
f.close()

但這樣寫太繁瑣了,每次讀檔或寫檔都樣寫這樣的程式碼的話顯得很冗長。

好在 Python 提供了 with open 語句來解決這個問題,使用 Python with open 語句可以自動地幫我們呼叫 close() 關檔的動作,即使在 Python with open 語句裡發生例外也是一樣,而且這也是官方建議使用的方式,我們來看看 Python with open 語句怎麼寫,將上述範例改用 Python with open 語句後如下列範例所示,

1
2
3
4
5
6
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

with open('xxx.txt', 'r') as f:
text = f.read()
print(text)

這寫法跟前述範例的 try… finially 寫法效果是一樣的,但是 Python with open 語句的程式碼明顯地更精簡更少,而且還不用呼叫 close() 函式關檔。

在某些情況下用 f.read() 是比較快速的選擇,例如檔案內容大小很小時,但有時可能不會採用一次全部讀取的方式,例如檔案內容超大無法一次讀取到記憶體,或者想要分批每次一行處理,如果是想每次處理一行的話可以使用 readlines() 搭配迴圈像這樣寫,

1
2
3
4
5
6
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

with open('xxx.txt', 'r') as f:
for line in f.readlines():
print(line)

Python open with 指定讀取檔案的編碼格式

Python open with 要指定讀取檔案的編碼格式,在 open() 設定 encoding 編碼格式即可,例如 Big-5 就這樣寫,

1
2
3
with open('xxx.txt', 'r', encoding='Big5') as f:
# or
f = open('xxx.txt', 'r', encoding='Big5')

UTF-8 就這樣寫,

1
2
3
with open('xxx.txt', 'r', encoding='UTF-8') as f:
# or
f = open('xxx.txt', 'r', encoding='UTF-8')

為了解決各種編碼問題,例如簡體中文與繁體中文,通常我們都會把編碼統一都轉成萬國碼 unicode。

如果遇到編碼錯誤,例如 UnicodeDecodeError,這可能是檔案中包含的未定義的編碼字元,遇到這種狀況如果要忽略的話,可以這樣寫,

1
2
3
with open('xxx.txt', 'r', encoding='Big5', errors='ignore') as f:
# or
f = open('xxx.txt', 'r', encoding='Big5', errors='ignore')

Python open with 開檔寫入文字檔

這邊介紹 Python open with 開檔寫入文字檔的範例,根據前述讀取文字檔介紹的差不多,在寫入文字檔時 open() 開檔要用 w 模式,

原本的開檔寫入文字檔的寫法為這樣,用 write() 將文字寫入檔案裡,在作業系統裡會有一個緩衝區,直到緩衝區滿了才會真正寫入硬碟裡,除非使用 flush() 強制將緩衝區寫入硬碟了,或者 close() 也會將緩衝區剩下的資料寫入硬碟裡,所以沒有正確 close() 關閉檔案的文字檔很容易看到檔案尾巴是資料不完整的狀況,

1
2
3
4
5
6
7
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

f = open('xxx.txt', 'w')
f.write('apple\n')
f.write('banana\n')
f.close()

所以這時要碼要用 try… finially 寫法來正確的處理例外以及關檔,或者可以使用 Python open with 的寫法,如下所示,

1
2
3
4
5
6
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

with open('xxx.txt', 'w') as f:
f.write('apple\n')
f.write('banana\n')

Python open with 開檔讀取二進制檔

上述範例都是介紹文字檔的讀取與寫入,這邊要介紹二進制檔案的讀取,Python open with 讀取二進制檔案就需要在開檔模式裡加上 'b' 表示 binary 二進制模式,例如:二進制讀檔就要用 'rb',在上傳圖片、影片或其它檔案時就會用二進制開檔讀取,

原本的開檔讀取二進制檔寫法為這樣,

1
2
3
f = open('xxx.bin', 'rb')
# f.read()
# ...

改成 Python open with 來開檔讀取二進制檔案的寫法就會是這樣寫,

1
2
3
with open('xxx.bin', 'rb') as f:
# f.read()
# ...

Python open with 開檔寫入二進制檔

這一節介紹 Python open with 寫入二進制檔案,跟上一節概念相似,

原本的開檔寫入二進制檔寫法為這樣,

1
2
3
f = open('xxx.bin', 'wb')
# f.write()
# ...

改成 Python open with 來開檔寫入二進制檔案的寫法就會是這樣寫,

1
2
3
with open('xxx.bin', 'wb') as f:
# f.write()
# ...

以上就是 Python open with 用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它相關文章推薦
Python 新手入門教學懶人包

Python string 轉 bytes 的 3 種方法

本篇 ShengYu 介紹 Python string 轉 bytes 的 3 種方法,

以下 Python 字串轉 bytes 的方法將分為這幾種,

  • Python 在字串前面加上 b
  • Python bytes 類別建構子
  • Python str.encode() 成員函式

那我們開始吧!

Python 在字串前面加上 b

在 Python 3 中在字串前面加上 b 表示這是 bytes,就會將這個字串轉成 bytes,

1
2
3
4
5
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

print(b'hello')
print(type(b'hello'))

結果輸出如下,

1
2
b'hello'
<class 'bytes'>

Python bytes 類別建構子

Python 3 也可以使用 bytes 類別的建構子來轉換字串,在 bytes 類別的建構子中帶入字串就會將字串轉成 bytes,預設編碼為 None,需要指定編碼否則會出現 TypeError 錯誤,

1
2
3
4
5
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

print(bytes('hello', 'utf-8'))
print(type(bytes('hello', 'utf-8')))

結果輸出如下,

1
2
b'hello'
<class 'bytes'>

Python str.encode() 成員函式

Python 3 使用 str.encode() 成員函式也可以將該字串轉成 bytes,encode() 預設編碼就是 'utf-8',有其它需求也可以指定其它編碼,

1
2
3
4
5
6
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

print('hello'.encode())
print(type('hello'.encode()))
print('hello'.encode(encoding='utf-8'))

結果輸出如下,

1
2
3
b'hello'
<class 'bytes'>
b'hello'

以上就是 Python string 轉 bytes 的 3 種方法介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它相關文章推薦
Python 新手入門教學懶人包