1. 程式人生 > 實用技巧 >C++指標基礎——交換兩個變數的值

C++指標基礎——交換兩個變數的值

一、普通檔案(無後綴名)

1.1 對檔案操作流程

  1. 開啟檔案,得到檔案控制代碼並賦值給一個變數

  2. 通過控制代碼對檔案進行操作

  3. 關閉檔案

    現有檔案如下:

昨夜寒蛩不住鳴。
驚回千里夢,已三更。
起來獨自繞階行。
人悄悄,簾外月朧明。
白首為功名,舊山松竹老,阻歸程。
欲將心事付瑤琴。
知音少,絃斷有誰聽。
f = open('小重山') #開啟檔案
data=f.read()#獲取檔案內容
f.close() #關閉檔案 ,如果沒有關閉,那在寫檔案的話,只到快取,沒有到硬碟。

​ 注意 if in the win,hello檔案是utf8儲存的,開啟檔案時open函式是通過作業系統開啟的檔案,而win作業系統預設的是gbk編碼,所以直接開啟會亂碼,需要f=open('hello',encoding='utf8')

,hello檔案如果是gbk儲存的,則直接開啟即可。

1.2 檔案開啟模式

========= ===============================================================
    Character Meaning
    --------- ---------------------------------------------------------------
    'r'       open for reading (default)
    'w'       open for writing, truncating the file first
    'x'       create a new file and open it for writing
    'a'       open for writing, appending to the end of the file if it exists
    'b'       binary mode
    't'       text mode (default)
    '+'       open a disk file for updating (reading and writing)
    'U'       universal newline mode (deprecated)
    ========= ===============================================================

​ 先介紹三種最基本的模式:r(只可讀) w(只可寫) a(追加)

f = open('小重山2','w') #開啟檔案,清空後再寫
f = open('小重山2','a') #開啟檔案,追加
f.write('莫等閒1\n')
f.write('白了少年頭2\n')
f.write('空悲切!3')

1.3 檔案具體操作

def read(self, size=-1): # known case of _io.FileIO.read
        """
        注意,不一定能全讀回來
        Read at most size bytes, returned as bytes.

        Only makes one system call, so less data may be returned than requested.
        In non-blocking mode, returns None if no data is available.
        Return an empty bytes object at EOF.
        """
        return ""

def readline(self, *args, **kwargs):
        pass

def readlines(self, *args, **kwargs):
        pass


def tell(self, *args, **kwargs): # real signature unknown
        """
        Current file position.

        Can raise OSError for non seekable files.
        """
        pass

def seek(self, *args, **kwargs): # real signature unknown
        """
        Move to new file position and return the file position.

        Argument offset is a byte count.  Optional argument whence defaults to
        SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values
        are SEEK_CUR or 1 (move relative to current position, positive or negative),
        and SEEK_END or 2 (move relative to end of file, usually negative, although
        many platforms allow seeking beyond the end of a file).

        Note that not all file objects are seekable.
        """
        pass

def write(self, *args, **kwargs): # real signature unknown
        """
        Write bytes b to file, return number written.

        Only makes one system call, so not all of the data may be written.
        The number of bytes actually written is returned.  In non-blocking mode,
        returns None if the write would block.
        """
        pass

def flush(self, *args, **kwargs):
        pass


def truncate(self, *args, **kwargs): # real signature unknown
        """
        Truncate the file to at most size bytes and return the truncated size.

        Size defaults to the current file position, as returned by tell().
        The current file position is changed to the value of size.
        """
        pass


def close(self): # real signature unknown; restored from __doc__
            """
            Close the file.

            A closed file cannot be used for further I/O operations.  close() may be
            called more than once without error.
            """
            pass
##############################################################less usefull
    def fileno(self, *args, **kwargs): # real signature unknown
            """ Return the underlying file descriptor (an integer). """
            pass

    def isatty(self, *args, **kwargs): # real signature unknown
        """ True if the file is connected to a TTY device. """
        pass

    def readable(self, *args, **kwargs): # real signature unknown
        """ True if file was opened in a read mode. """
        pass

    def readall(self, *args, **kwargs): # real signature unknown
        """
        Read all data from the file, returned as bytes.

        In non-blocking mode, returns as much as is immediately available,
        or None if no data is available.  Return an empty bytes object at EOF.
        """
        pass

    def seekable(self, *args, **kwargs): # real signature unknown
        """ True if file supports random-access. """
        pass


    def writable(self, *args, **kwargs): # real signature unknown
        """ True if file was opened in a write mode. """
        pass

操作方法介紹

f = open('小重山') #開啟檔案
# data1=f.read()#獲取檔案內容
# data2=f.read()#獲取檔案內容
#
# print(data1)
# print('...',data2)
# data=f.read(5)#獲取檔案內容,漢字在這裡佔一個單位(in Py3)
 
# data=f.readline()  #無論是read()還是readline(),游標會發生位置變化
# print(f.__iter__().__next__())
# for i in range(5):
#     print(f.readline())
 
# data=f.readlines()['昨夜寒蛩不住鳴。\n', '驚回千里夢,已三更。\n', '起來獨自繞階行。\n', '人悄悄,簾外月朧明。\n', '白首為功名,舊山松竹老,阻歸程。\n', '欲將心事付瑤琴。\n', '知音少,絃斷有誰聽。']
 
# for line in f.readlines():
#     print(line)
 
 
# 問題來了:列印所有行,另外第3行後面加上:'end 3'
# for index,line in enumerate(f.readlines()):
#     if index==2:
#         line=''.join([line.strip(),'end 3'])
#     print(line.strip())
 
#切記:以後我們一定都用下面這種
# count=0 
# for line in f:          # 這是for內部將 f 物件做成一個迭代器,用一行去一行。
#     if count==3: 
#         line=''.join([line.strip(),'end 3'])
#     print(line.strip())
#     count+=1
 
# print(f.tell())
# print(f.readline())
# print(f.tell())       #tell對於英文字元就是佔一個,中文字元佔三個,區分與read()的不同.
# print(f.read(5))      #一箇中文佔三個位元組
# print(f.tell())
# f.seek(0)             #跟tell相對,人為設定位置
# print(f.read(6))     #read後不管是中文字元還是英文字元,都統一算一個單位,read(6),此刻就讀了6箇中文字元
 
#terminal上操作:
f = open('小重山2','w')
# f.write('hello \n')
# f.flush()              #flush():同步把將資料從快取轉移到磁碟上去
# f.write('world')
 
# 應用:進度條
# import time,sys
# for i in range(30):
#     sys.stdout.write("*")
#     # sys.stdout.flush()
#     time.sleep(0.1)

# import sys,time
# for i in range(30):
#    print('*',end='',flush=True)
#    time.sleep(0.1)


# f = open('小重山2','w')
# f.truncate()           #全部截斷
# f.truncate(5)          #之後的全截斷,游標跟seek一樣,按位元組算,不按字元算。這裡5會出亂碼,因為漢字是3個位元組一個字元
 
 
# print(f.isatty())      # isatty() 方法檢測檔案是否連線到一個終端裝置,如果是返回 True,否則返回 False。
# print(f.seekable())
# print(f.readable())
 
f.close() #關閉檔案

接下來我們繼續擴充套件檔案模式:

# f = open('小重山2','w') #開啟檔案
# f = open('小重山2','a') #開啟檔案
# f.write('莫等閒1\n')
# f.write('白了少年頭2\n')
# f.write('空悲切!3')
 
 
# f.close()
 
#r+,w+模式
# f = open('小重山2','r+') #以讀寫模式開啟檔案
# print(f.read(5))#可讀
# f.write('hello')
# print('------')
# print(f.read())
 
 
# f = open('小重山2','w+') #以寫讀模式開啟檔案
# print(f.read(5))#什麼都沒有,因為先格式化了文字
# f.write('hello alex')
# print(f.read())#還是read不到
# f.seek(0)
# print(f.read())
 
#w+與a+的區別在於是否在開始覆蓋整個檔案
 
 
# ok,重點來了,我要給文字第三行後面加一行內容:'hello 岳飛!'
# 有同學說,前面不是做過修改了嗎? 大哥,剛才是修改內容後print,現在是對檔案進行修改!!!
# f = open('小重山2','r+') #以寫讀模式開啟檔案
# f.readline()
# f.readline()
# f.readline()
# print(f.tell())
# f.write('hello 岳飛')
# f.close()
# 和想的不一樣,不管事!那涉及到檔案修改怎麼辦呢?
 
# f_read = open('小重山','r') #以寫讀模式開啟檔案
# f_write = open('小重山_back','w') #以寫讀模式開啟檔案
 
# count=0
# for line in f_read:
    # if count==3:
    #     f_write.write('hello,岳飛\n')
    #
    # else:
    #     f_write.write(line)
 
 
    # another way:
    # if count==3:
    #
    #     line='hello,岳飛2\n'
    # f_write.write(line)
    # count+=1
 
 
# #二進位制模式
# f = open('小重山2','wb') #以二進位制的形式讀檔案
# # f = open('小重山2','wb') #以二進位制的形式寫檔案
# f.write('hello alvin!'.encode())#b'hello alvin!'就是一個二進位制格式的資料,只是為了觀看,沒有顯示成010101的形式

注意1: 無論是py2還是py3,在r+模式下都可以等量位元組替換,但沒有任何意義的! 

注意2:有同學在這裡會用readlines得到內容列表,再通過索引對相應內容進行修改,最後將列表重新寫會該檔案。

​ 這種思路有一個很大的問題,資料若很大,你的記憶體會受不了的,而我們的方式則可以通過迭代器來優化這個過程。 

補充:rb模式以及seek

fileObject.seek(offset[, whence])

offset -- 開始的偏移量,也就是代表需要移動偏移的位元組數
whence:可選,預設值為 0。給offset引數一個定義,表示要從哪個位置開始偏移;0代表從檔案開頭開始算起,1代表從當前位置開始算起,2代表從檔案末尾算起。

在py2中:

#昨夜寒蛩不住鳴.
 
f = open('test','r',) #以寫讀模式開啟檔案
 
f.read(3)
 
# f.seek(3)
# print f.read(3) # 夜
 
# f.seek(3,1)
# print f.read(3) # 寒
 
# f.seek(-4,2)
# print f.read(3) # 鳴

在py3中:

# test: 
昨夜寒蛩不住鳴.

f = open('test','rb',) #以寫讀模式開啟檔案

f.read(3)

# f.seek(3)
# print(f.read(3)) # b'\xe5\xa4\x9c'

# f.seek(3,1)      #第一個數表示偏移量,第二個數表示從哪個位置開始偏移。
# print(f.read(3)) # b'\xe5\xaf\x92'

# f.seek(-4,2)
# print(f.read(3))   # b'\xe9\xb8\xa3'

#總結: 在py3中,如果你想要字元資料,即用於觀看的,則用r模式,這樣我f.read到的資料是一個經過decode的
#     unicode資料; 但是如果這個資料我並不需要看,而只是用於傳輸,比如檔案上傳,那麼我並不需要decode
#     直接傳送bytes就好了,所以這個時候用rb模式.

#     在py3中,有一條嚴格的線區分著bytes和unicode,比如seek的用法,在py2和py3裡都是一個個位元組的seek,
#     但在py3裡你就必須宣告好了f的型別是rb,不允許再模糊.

#建議: 以後再讀寫檔案的時候直接用rb模式,需要decode的時候仔顯示地去解碼.

1.4 with

​ 為了避免開啟檔案後忘記關閉,可以通過管理上下文,即:

with open('log','r') as f:
        pass

​ 如此方式,當with程式碼塊執行完畢時,內部會自動關閉並釋放檔案資源。

​ 在Python 2.7 後,with又支援同時對多個檔案的上下文進行管理,即:

with open('log1') as obj1, open('log2') as obj2:
    pass

1.5 修改檔案

# 修改檔案
with open('小護士班主任',encoding='utf-8') as f,open('小護士班主任.bak','w',encoding='utf-8') as f2:
    for line in f:
        if '星兒' in line:  #班主任:星兒
            line = line.replace('星兒','啊嬌')
        #寫檔案
        f2.write(line) #小護士:金老闆

import os
os.remove('小護士班主任') #刪除檔案
os.rename('小護士班主任.bak','小護士班主任')  #重新命名檔案

二、csv

2.1 csv簡介

​ CSV (Comma Separated Values),即逗號分隔值(也稱字元分隔值,因為分隔符可以不是逗號),是一種常用的文字格式,用以儲存表格資料,包括數字或者字元。很多程式在處理資料時都會碰到csv這種格式的檔案,它的使用是比較廣泛的(Kaggle上一些題目提供的資料就是csv格式),csv雖然使用廣泛,但卻沒有通用的標準,所以在處理csv格式時常常會碰到麻煩,幸好python內建了csv模組。下面簡單介紹csv模組中最常用的一些函式。

  一般我們用的execl生成的格式是xls和xlsx 直接重新命名為csv的話會報錯。

2.2 csv模組中的函式

2.2.1 reader

reader(csvfile, dialect='excel', **fmtparams)

csvfile,必須是支援迭代(Iterator)的物件,可以是檔案(file)物件或者列表(list)物件,如果是檔案物件,開啟時需要加"b"標誌引數。

dialect,編碼風格,預設為excel的風格,也就是用逗號(,)分隔,dialect方式也支援自定義,通過呼叫register_dialect方法來註冊,下文會提到。

fmtparam,格式化引數,用來覆蓋之前dialect物件指定的編碼風格。

import csv  
with open('test.csv','r') as myFile:  
    lines=csv.reader(myFile)  
    for line in lines:  
        print(line)  

>>>
['testing', '[email protected]', '23', 'man']
['testing2', '[email protected]', '34', 'woman']
['testing3', '[email protected]', '22', 'man']

***Repl Closed***
'test.csv'是檔名,‘rb’中的r表示“讀”模式,因為是檔案物件,所以加‘b’。
open()返回了一個檔案物件myFile,reader(myFile)只傳入了第一個引數,另外兩個引數採用預設值,即以excel風格讀入。
reader()返回一個reader物件lines,lines是一個list,當呼叫它的方法lines.next()時,會返回一個string。
上面程式的效果是將csv檔案中的文字按行列印,每一行的元素都是以逗號分隔符','分隔得來。

補充:reader物件還提供一些方法:line_num、dialect、next()

2.2.2 writer

writer(csvfile, dialect='excel', **fmtparams)

引數的意義同 reader,這裡不贅述。
import csv

with open('test.csv','w') as myFile:      
    myWriter=csv.writer(myFile)  
    myWriter.writerow([7,'g'])  
    myWriter.writerow([8,'h'])  
    myList=[[1,2,3],[4,5,6]]  
    myWriter.writerows(myList)

 

 有空行,看著非常難受,以下方式解決。

import csv

with open('test.csv','w',newline="") as myFile:      
    myWriter=csv.writer(myFile)  
    myWriter.writerow([7,'g'])  
    myWriter.writerow([8,'h'])  
    myList=[[1,2,3],[4,5,6]]  
    myWriter.writerows(myList)

'w'表示寫模式。
首先open()函式開啟當前路徑下的名字為't.csv'的檔案,如果不存在這個檔案,則建立它,返回myFile檔案物件。
csv.writer(myFile)返回writer物件myWriter。
writerow()方法是一行一行寫入,writerows方法是一次寫入多行。
注意:如果檔案't.csv'事先存在,呼叫writer函式會先清空原檔案中的文字,再執行writerow/writerows方法。

補充:除了writerow、writerows,writer物件還提供了其他一些方法:writeheader、dialect

csv 暫時就先寫這些了。其他的需要用的時候繼續補充。

三、excel

python中與excel操作相關的模組:

  • xlrd庫:從excel中讀取資料,支援xls、xlsx
  • xlwt庫:對excel進行修改操作,不支援對xlsx格式的修改
  • xlutils庫:在xlw和xlrd中,對一個已存在的檔案進行修改。
  • openpyxl:主要針對xlsx格式的excel進行讀取和編輯。

3.1 Excel 中的三大物件

  • WorkBook:工作簿物件
  • Sheet:表單物件
  • Cell:表格物件

3.2 安裝

pip install openpyxl

3.3 開啟檔案

1、建立

from  openpyxl import  Workbook 
# 例項化
wb = Workbook()
# 啟用 worksheet
ws = wb.active

2、開啟已有

>>> from openpyxl  import load_workbook
>>> wb2 = load_workbook('檔名稱.xlsx')

3.4 儲存資料

# 方式一:資料可以直接分配到單元格中(可以輸入公式)
ws['A1'] = 42
# 方式二:可以附加行,從第一列開始附加(從最下方空白處,最左開始)(可以輸入多行)
ws.append([1, 2, 3])
# 方式三:Python 型別會被自動轉換
ws['A3'] = datetime.datetime.now().strftime("%Y-%m-%d")

3.5 建立表(sheet)

# 方式一:插入到最後(default)
ws1 = wb.create_sheet("Mysheet") 
# 方式二:插入到最開始的位置
ws2 = wb.create_sheet("Mysheet", 0)

3.6 選擇表(sheet)

# sheet 名稱可以作為 key 進行索引
>>> ws3 = wb["New Title"]
>>> ws4 = wb.get_sheet_by_name("New Title")
>>> ws is ws3 is ws4
True

3.7 查看錶名(sheet)

# 顯示所有表名
print(wb.sheetnames)
['Sheet2', 'New Title', 'Sheet1']
# 遍歷所有表
for sheet in wb:
	print(sheet.title)

3.8 訪問單元格(call)

1、單一單元格訪問

# 方法一
c = ws['A4']
# 方法二:row 行;column 列
d = ws.cell(row=4, column=2, value=10)
# 方法三:只要訪問就建立
for i in range(1,101):
	for j in range(1,101):
		ws.cell(row=i, column=j)

2、多單元格訪問

# 通過切片
>>> cell_range = ws['A1':'C2']
# 通過行(列)
>>> colC = ws['C']
>>> col_range = ws['C:D']
>>> row10 = ws[10]
>>> row_range = ws[5:10]
# 通過指定範圍(行 → 行)
>>> for row in ws.iter_rows(min_row=1, max_col=3, max_row=2):
...  for cell in row:
...    print(cell)
<Cell Sheet1.A1>
<Cell Sheet1.B1>
<Cell Sheet1.C1>
<Cell Sheet1.A2>
<Cell Sheet1.B2>
<Cell Sheet1.C2> 
# 通過指定範圍(列 → 列)
for row in ws.iter_cols(min_col=1, max_row=3, max_col=2):
    for cell in row:
        print(cell)
<Cell 'Sheet'.A1>
<Cell 'Sheet'.A2>
<Cell 'Sheet'.A3>
<Cell 'Sheet'.B1>
<Cell 'Sheet'.B2>
<Cell 'Sheet'.B3>
# 遍歷所有 方法一
>>> ws = wb.active
>>> ws['C9'] = 'hello world'
>>> tuple(ws.rows)
((<Cell Sheet.A1>, <Cell Sheet.B1>, <Cell Sheet.C1>),
(<Cell Sheet.A2>, <Cell Sheet.B2>, <Cell Sheet.C2>),
...
(<Cell Sheet.A8>, <Cell Sheet.B8>, <Cell Sheet.C8>),
(<Cell Sheet.A9>, <Cell Sheet.B9>, <Cell Sheet.C9>))
# 遍歷所有 方法二
>>> tuple(ws.columns)
((<Cell Sheet.A1>,
<Cell Sheet.A2>,
<Cell Sheet.A3>,
...
<Cell Sheet.B7>,
<Cell Sheet.B8>,
<Cell Sheet.B9>),
(<Cell Sheet.C1>,
...
<Cell Sheet.C8>,
<Cell Sheet.C9>))

3.9 儲存資料

wb.save('檔名稱.xlsx')

3.10 其他

1、改變 sheet 標籤按鈕顏色

ws.sheet_properties.tabColor = "1072BA"

2、獲取最大行,最大列

# 獲得最大列和最大行
print(sheet.max_row)
print(sheet.max_column)

3、獲取每一行,每一列

  • sheet.rows為生成器, 裡面是每一行的資料,每一行又由一個tuple包裹。
  • sheet.columns類似,不過裡面是每個tuple是每一列的單元格。

# 因為按行,所以返回A1, B1, C1這樣的順序
for row in sheet.rows:
  for cell in row:
    print(cell.value)
 
# A1, A2, A3這樣的順序
for column in sheet.columns:
  for cell in column:
    print(cell.value)

4、根據數字得到字母,根據字母得到數字

from openpyxl.utils import get_column_letter, column_index_from_string
# 根據列的數字返回字母
print(get_column_letter(2))  # B
# 根據字母返回列的數字
print(column_index_from_string('D'))

5、刪除工作表

# 方式一
wb.remove(sheet)
# 方式二
del wb[sheet]

6、矩陣置換(行 → 列)

rows = [
    ['Number', 'data1', 'data2'],
    [2, 40, 30],
    [3, 40, 25],
    [4, 50, 30],
    [5, 30, 10],
    [6, 25, 5],
    [7, 50, 10]]
 
list(zip(*rows))
 
# out
[('Number', 2, 3, 4, 5, 6, 7),
 ('data1', 40, 40, 50, 30, 25, 50),
 ('data2', 30, 25, 30, 10, 5, 10)]
 
# 注意 方法會捨棄缺少資料的列(行)
rows = [
    ['Number', 'data1', 'data2'],
    [2, 40	  ],	# 這裡少一個數據
    [3, 40, 25],
    [4, 50, 30],
    [5, 30, 10],
    [6, 25, 5],
    [7, 50, 10],
]
# out
[('Number', 2, 3, 4, 5, 6, 7), ('data1', 40, 40, 50, 30, 25, 50)]

3.11 設定單元格風格

1、需要匯入的類

from openpyxl.styles import Font, colors, Alignment

2、字型

​ 下面的程式碼指定了等線24號加粗斜體,字型顏色紅色。直接使用cell的font屬性,將Font物件賦值給它。

bold_itatic_24_font = Font(name='等線', size=24, italic=True, color=colors.RED, bold=True)
sheet['A1'].font = bold_itatic_24_font

3、對齊方式

​ 也是直接使用cell的屬性aligment,這裡指定垂直居中和水平居中。除了center,還可以使用right、left等等引數。

# 設定B1中的資料垂直居中和水平居中
sheet['B1'].alignment = Alignment(horizontal='center', vertical='center')

4、設定行高和列寬

# 第2行行高
sheet.row_dimensions[2].height = 40
# C列列寬
sheet.column_dimensions['C'].width = 30

5、合併和拆分單元格

# 合併單元格, 往左上角寫入資料即可
sheet.merge_cells('B1:G1') # 合併一行中的幾個單元格
sheet.merge_cells('A1:C3') # 合併一個矩形區域中的單元格