1. 程式人生 > 其它 >學習python,從入門到放棄(10)

學習python,從入門到放棄(10)

學習python,從入門到放棄(10)

檔案內的游標移動

  • 基本移動

    read 在文字模式下,括號內的數字表示的是讀取指定的字元個數,但不會從頭讀取,會繼續讀取。

    with open(r'a.txt', 'r', encoding='utf8') as f:
        print(f.read(3))  # hel
        print(f.read(3))  # lo
    

    read 在二進位制模式下,括號內的數字表示的是讀取指定的位元組數 unicode 所有的字元都是用 2bytes 表示一個字元,而utf8中文用 3bytes 來表示一個字元,英文用 1bytes 來表示一個字元,同樣是繼續讀取。

    with open(r'a.txt', 'rb') as f:
        print(f.read(9).decode('utf8'))  # hello wor
        print(f.read(1).decode('utf8'))  # l
    
  • 控制移動

    .seek() 方法可以控制游標的移動,在文字模式下移動的單位也是位元組數。

    .seek(offset,whence)

    offset :控制移動的位元組數

    whence:控制模式

    控制模式0:讓游標先移動到檔案開頭,支援文字模式和二進位制模式

    控制模式1:讓游標先停留在當前位置,只支援二進位制模式

    控制模式2:讓游標先移動到檔案末尾,只支援二進位制模式

    with open(r'a.txt','r',encoding='utf8') as f:
        print(f.read())  # hello world你好世界
        f.seek(3, 0)
        print(f.read())  # lo world你好世界
    
    with open(r'a.txt', 'rb') as f:
        print(f.read(3).decode('utf8'))  # hel
        f.seek(3, 1)  # 基於當前位置 繼續往後移動三個位元組
        f.seek(-3, 2)  # 基於檔案末尾 往前移動三個位元組
        print(f.tell())  # 獲取游標基於檔案開頭的位元組數 20
        print(f.read().decode('utf8'))  # 界
    

檔案的修改

硬碟上的資料有兩個狀態,佔有態與自由態,我們刪除資料其實就是將資料原來的位置標記成自由態,之後如果有新的資料進來了並且落到了自由態位置那麼直接覆蓋。所以自己不用的手機和電腦,不要直接賣掉,應該先刪除所有的資料,然後找一些無關緊要的資料儲存一遍。

將檔案內容發一次性全部讀入記憶體,然後在記憶體中修改完畢後再覆蓋寫回原檔案,優點是在檔案修改過程中同一份資料只有一份,缺點是會過多地佔用記憶體。

with open('b.txt', mode='r', encoding='utf-8') as f:
    data = f.read()
    print(data)
with open('b.txt', mode='w', encoding='utf-8') as f:
    f.write(data.replace('hello', '你好'))
with open('b.txt', mode='r', encoding='utf-8') as f:
    data = f.read()
    print(data)

也可以以讀的方式開啟原檔案,以寫的方式開啟一個臨時檔案,一行行讀取原檔案內容,修改完後寫入臨時檔案,刪掉原檔案,將臨時檔案重新命名原檔名。優點是不會佔用過多的記憶體,缺點是在檔案修改過程中同一份資料存了兩份。

import os
with open('b.txt', 'r', encoding='utf-8') as read_f, \
        open('.b.txt.swap', 'w', encoding='utf-8') as wrife_f:
    for line in read_f:
        wrife_f.write(line.replace('你好', 'hello'))
os.remove('b.txt')  # 刪除檔案
os.rename('.b.txt.swap', 'b.txt')  # 重新命名檔案
# 你好 world 》》》hello world

函式

自定義函式,當我們需要在不同的地方完成相同的操作時,編寫兩段一樣的程式碼就顯得很冗長很沒有美感,這時候就需要自己定義一個函式,將這個操作放在這個函式裡,當需要時就可以直接拿來使用了。

s = 'hello world'
print(len(s))  # 11

def my_len():
    n = 0
    for i in s:
        n += 1
    print('字串中字元的個數',n)

my_len()  # 字串中字元的個數 11
  • 語法結構

    def 函式名(引數1,引數2):
        '''函式的註釋'''
        函式體程式碼
        return 返回值
    

    def 用於告訴計算機下面我要開始自定義函式啦

    函式名類似與變數名,當我們要用這個函式時直接寫它的函式名就可以使用了

    括號要緊跟在函式名後面

    引數用於在使用函式時進行內部資料的傳遞。

    冒號表示需要縮排的程式碼塊

    函式的註釋可以告訴別人該函式的用途

    函式體程式碼是函式的核心功能,是我們需要編寫的核心

    return後面跟著返回值,表面需要返回的資料是什麼

    定義函式的過程不會執行函式體程式碼,只會檢測語法。

總結

今天學習了昨天檔案操作的補充,還有學習了新的自定義函式,自定義函式學會了之後會使我們的程式碼更加簡練也會更加美觀。

作業

嘗試著使用函式寫註冊登入

但是我寫了 cmd 的部分

import pathlib


chances = 1
is_l_again = False
is_run = True

path = pathlib.Path("userinfo.txt")  # 當不存在userinfo時自動建立,其中只有一個使用者jason
if not path.is_file():
    with open('userinfo.txt', 'w', encoding='utf8') as f:
        f.write('jason|123')


def cmd():
    """
    登入成功後的cmd
    """
    print('登入成功,歡迎你,%s' % in_username)
    print('輸入quit退出系統')
    while True:
        cmd = input('>>>')
        if cmd == 'quit':
            print("再見,%s" % in_username)
            break
        else:
            print(cmd)
    return None


while is_run:
    username = []
    password = []
    with open('userinfo.txt', 'r', encoding='utf8') as f:
        data = f.readlines()
    for i in range(len(data)):
        username.append(data[i].split('|')[0])
        password.append(data[i].split('|')[1])
    l_or_r = input('登入/註冊?請輸入L/R')
    if l_or_r == 'l' or l_or_r == 'L':
        while chances <= 3:
            in_username = input('username:').strip()
            in_password = input('password:').strip()
            if in_username in username and in_password == password[username.index(in_username)]:
                cmd()
                is_run = False
                break
            else:
                print('使用者名稱或密碼錯誤,剩餘嘗試次數為 %d 次' % (3 - chances))
                if chances == 3:
                    while True:
                        again = input('是否再次嘗試 y/n')
                        if again == 'y' or again == 'Y':
                            is_l_again = True
                            break
                        elif again == 'n' or again == 'N':
                            break
                        else:
                            print("請輸入y/n")
                            continue
                chances += 1
                if is_l_again:
                    chances = 1
                    is_l_again = False
    elif l_or_r == 'r' or l_or_r == 'R':
        while True:
            in_username = input('username:').strip()
            if in_username in username:
                print('使用者名稱已存在,請重新輸入,如已註冊,想返回登入介面在 username 處輸入:back')
                continue
            elif in_username == 'back':
                break
            in_password1 = input('password:').strip()
            in_password2 = input('password again:').strip()
            if in_password1 != in_password2:
                print('兩次輸入的密碼不一致,請重新輸入')
                continue
            else:
                print('註冊成功')
                with open('userinfo.txt', 'a', encoding='utf8') as f:
                    f.write('\n')
                    f.write(in_username)
                    f.write('|')
                    f.write(in_password1)
                cmd()
                is_run = False
                break