

utf-8形式のテキストファイルへ以下のコードで書き出し、再度インポートを行うとbase64のデータをstring型で保持してしまい、元の変数のデータと一致が取れなくなってしまう。

[code]

    base64.b64encode(string型変数.encode())
    
[/code]

### 下記状況

インポートしたテキストの状態 = b'abc'（※string型）  
base64.b64encode(string型変数.encode()) = b'abc'（※bytes型）

if文内でインポートしたテキストと変換元のワードが一致するかチェック処理を行いたいが、インポートしたテキストがstring型の状態でbase64時のテキストを保持しており、デコードができない。

**出てくるエラー:**

[code]

    'str' object has no attribute 'decode'
    
[/code]

エンコード元の変数をインポートした直後の状態に合わせようとするとbyte型からstring変換できません（当たり前）  

どのようにすれば一致させることができますか？  
また、以下のエラーをなんと解釈するべきかわからないのですが教えていただけますでしょうか。

[code]

    エラーコード'utf-8' codec can't decode byte 0xcd in position 3: invalid continuation byte
    
[/code]


CC BY-SA 4.0
2022-10-17T10:19:25.737
91651
2022-10-21T14:00:50.993
2022-10-18T02:34:25.360
51823
51823
question
python python3 base64
base64変換した文字列をテキストファイルとしてエクスポートすると再インポートした時、値が一致させる方法がわからない


色々模索した結果、以下の方法で解決に至りました。  
また、未解決部分までの再現コードも書き残します。

[code]

    # text.py
    # ※書き出しファイルのディレクトリをCドライブ直下（仮）にしているため、
    #   pyファイル実行時にアナコンダプロンプトを管理者権限で実行する前提
    import base64
    
    #書き出すテキスト
    inputTxt = 'aiueotext'
    print(inputTxt , type(inputTxt))
    #=> aiueotext <class 'str'>
    
    exportText = base64.b64encode(inputTxt.encode()) #...■１
    
    print(exportText , type(exportText))
    #=> b'YWl1ZW90ZXh0' <class 'bytes'>
    
    #書き出し
    txtfl = open('C:\\textfile_utf8.txt', 'w')
    txtfl.write(str(exportText))
    txtfl.close()
    
    #読み込み
    readfl = open('C:\\textfile_utf8.txt', 'r')
    txt = readfl.read()
    readfl.close()
    
    print(txt , type(txt))
    #=> b'YWl1ZW90ZXh0' <class 'str'>
    #これが型がbytes型とstr型で異なる為、値が同一と判定できなかった
    
    
    #ここまでが再現コード
    
    
    #解決方法
    
    # txt と　inputTxt の一致が取りたかったが、
    # 以下の記述で読み込みファイル側のデータを何とかエンコードできました。
    #base64.b64decode(txt[2:-1].encode()).decode('utf-8')
    
    txt = base64.b64decode(txt[2:-1].encode()).decode('utf-8') #...■２
    
    print(txt , type(txt))
    #=> aiueotext <class 'str'>
    
[/code]

追記：  
デコードするときに変数の一部を除外する処理に納得できなかったので調べたところ、  
以下のような対応で処理することができました。

[code]

    #修正箇所
    #...■１
    exportText = base64.b64encode(inputTxt.encode()).decode('utf-8')
    
    #...■２
    txt = base64.b64decode(txt.encode()).decode('utf-8')
    
[/code]


CC BY-SA 4.0
2022-10-18T02:13:03.320
91657
2022-10-18T03:50:57.833
2022-10-18T03:50:57.833
3060
51823
91651
answer


`b'YWl1ZW90ZXh0'`という **長さ12** のデータを

[code]

    txtfl = open('C:\\textfile_utf8.txt', 'w')
    txtfl.write(str(exportText))
    txtfl.close()
    
[/code]

で書き出した時、 **15バイトに増えていた** ことに疑問は無かったでしょうか。

ファイルに書かれた `b''`の部分に疑問を感じなかったのでしょうか。

それが本当にbase64でエンコードされたデータの一部だと思っていたのでしょうか。

**そもそもファイルの中身を見たのでしょうか。**

bytes型のデータを書き出すのにテキストモードでファイルを開いて、Pythonでのリテラルを表現する余計なもの(`b''`のこと)が付いた状態で書き出してのが失敗です。

bytes型とstr型の理解がまだのようですのでそのあたりを触ってみるとよさそうですが、それはおいておいて、こうなっていればよかったであろうコードを書いておきます。

[code]

    import base64
    
    # 書き出すテキスト
    inputTxt = 'aiueotext'
    print(inputTxt , type(inputTxt))
    #=> aiueotext <class 'str'>
    
    # UTF-8でデコードして得たbytes型のデータを、base64でエンコードする
    exportText = base64.b64encode(inputTxt.encode())
    
    print(exportText , type(exportText))
    #=> b'YWl1ZW90ZXh0' <class 'bytes'>
    
    # バイナリモードで書き出し
    binfl = open('textfile_ascii.txt', 'wb')
    binfl.write(exportText)
    binfl.close()
    
    # バイナリモードで読み込み
    readfl = open('textfile_ascii.txt', 'rb')
    txt_as_bytes = readfl.read()
    readfl.close()
    
    print(txt_as_bytes , type(txt_as_bytes))
    # => b'YWl1ZW90ZXh0' <class 'bytes'>
    
    # base64でデコードしたbytes型のデータを、UTF-8でデコードしてstr型を得る
    txt = base64.b64decode(txt_as_bytes).decode()
    
    print(txt , type(txt))
    # => aiueotext <class 'str'>
    
[/code]

* * *

ところで

<https://docs.python.org/ja/3/library/base64.html#base64.b64decode>

> Base64 エンコードされた bytes-like object または ASCII 文字列 s をデコードし、デコードされた bytes
> を返します。

なので読み込みの方は

[code]

    # ファイルの中身は間違いなくasciiの範囲内なのでエンコーディングの指定が
    # UTF-8だろうがasciiだろうがShift-JISだろうが結果は変わらない
    readfl = open('textfile_ascii.txt', 'r')
    txt_as_str = readfl.read()
    readfl.close()
    
    print(txt_as_str , type(txt_as_str))
    # => YWl1ZW90ZXh0 <class 'str'>
    
    # base64でデコードしたbytes型のデータを、UTF-8でデコードしてstr型を得る
    txt = base64.b64decode(txt_as_bytes).decode()
    
    print(txt , type(txt))
    # => aiueotext <class 'str'>
    
[/code]

でもいいですね。


CC BY-SA 4.0
2022-10-18T16:14:37.550
91667
2022-10-18T16:14:37.550
12274
91651
answer


コメントで御指摘のように質問の仕方には多少なりとも難はありましたが，質問された方がコメントに対応してコードを提供して頂いたので，個人的には
pythonによる Base64 処理について改めて学ぶ機会を得ました。

そこで，質問された方の追記の方法を日本語の文字列でも確かめてみたところ，少なくとも私の環境（MacOS 12.6, Terminal(utf-8),
Python 3.10.8）では問題なさそうでした。御参考までにコードと出力を転記いたします。

[code]

    import base64
    
    input_str = ('文字列を Base64 エンコードして'
                 'テキストファイルに書き込む\n'
                 'テキストファイルを読み込み'
                 ' Base64 デコードして文字列を取得\n')
    print(f'input_str:\n{input_str}')
    
    write_str = base64.b64encode(input_str.encode()).decode()
    
    with open('tmp_base64.txt', 'w') as f:
        f.write(write_str)
    
    with open('tmp_base64.txt', 'r') as f:
        read_str = f.read()
    
    return_str = base64.b64decode(read_str).decode()
    print(f'return_str:\n{return_str}')
    
    print(f'input_str == return_str:\n{input_str == return_str}')
    
[/code]

[code]

    input_str:
    文字列を Base64 エンコードしてテキストファイルに書き込む
    テキストファイルを読み込み Base64 デコードして文字列を取得
    
    return_str:
    文字列を Base64 エンコードしてテキストファイルに書き込む
    テキストファイルを読み込み Base64 デコードして文字列を取得
    
    input_str == return_str:
    True
    
[/code]


CC BY-SA 4.0
2022-10-21T14:00:50.993
91729
2022-10-21T14:00:50.993
54588
91651
answer