61656


ファイルの中身を読んだ後中身を書き換えたいです

[code]

    with open('tmp.txt', mode='r+') as f:
        f.seek(0)
        f.write('100')
        f.seek(0)
        print(f.read())
        f.seek(0)
        f.write('10')
        f.seek(0)
        print(f.read()) # 100 のまま
    
[/code]

たとえば100って文字が書かれてるファイルから100を読んだあと  
10 で上書きしようとしたんですが  
任意の位置の文字を変更したりのばしたりはできるんですが  
縮めるというか任意の位置をファイルの終わりにするにはどうかけばいいのでしょうか

read したあと１回とじて w モードで開けばできるとはおもうんですが  
システムコールは重いってきいたことがあるので１度にやる方法ってないんでしょうか


CC BY-SA 4.0
2019-12-21T16:24:45.093
61655
2019-12-21T19:11:14.363
question
python file-io
r+ で開いたファイルを短くする方法


[io](https://docs.python.org/ja/3/library/io.html#io.IOBase.truncate) モジュールの
[truncate(size=None)](https://docs.python.org/ja/3/library/io.html#io.IOBase.truncate)
で出来ますよ。

> ストリームのサイズを、指定された size バイト (または size が指定されていない場合、現在位置)
> に変更します。現在のストリーム位置は変更されません。このサイズ変更により、現在のファイルサイズを拡大または縮小させることができます。拡大の場合には、新しいファイル領域の内容はプラットホームによって異なります
> (ほとんどのシステムでは、追加のバイトが 0 で埋められます)。新しいファイルサイズが返されます。
>
> バージョン 3.5 で変更: Windows で、拡大時に追加領域を 0 で埋めるようになりました。

ただ、普通のファイルなら問題無いですが、以下がFalseの場合はエラーになります。

>
> [seekable()](https://docs.python.org/ja/3/library/io.html#io.IOBase.seekable)  
>  ストリームがランダムアクセスをサポートしている場合、 True を返します。 False の場合、 seek()、 tell()、
> truncate() を使用すると OSError を発生させます。
>
>
> [writable()](https://docs.python.org/ja/3/library/io.html#io.IOBase.writable)  
>  ストリームが書き込みをサポートしている場合 True を返します。 False の場合は write()、 truncate() は OSError
> を返します。


CC BY-SA 4.0
2019-12-21T16:34:56.163
61656
2019-12-21T16:40:39.580
2020-06-17T08:14:45.997
-1
26370
61655
answer


質問の趣旨からは外れますが、[contextlib — Utilities for with-statement
contexts](https://docs.python.org/3.7/library/contextlib.html) を利用して `with
statement` を作成しても良いかもしれません。

[code]

    import contextlib
    import types
    
    @contextlib.contextmanager
    def overwrite(f, mode='w+'):
      def write_truncate(self, text):
        self.seek(0)
        self.write(text)
        self.truncate()
    
      def rewind_read(self):
        self.seek(0)
        return self.read()
    
      fx = open(f, mode)
      fx.rewind_read = types.MethodType(rewind_read, fx)
      fx.write_truncate = types.MethodType(write_truncate, fx)
      try:
        yield fx
      finally:
        fx.close()
    
    if __name__ == '__main__':
      with overwrite('tmp.txt', mode='r+') as f:
        f.write_truncate('100')
        print(f.rewind_read())
        f.write_truncate('10')
        print(f.rewind_read())
    
[/code]


CC BY-SA 4.0
2019-12-21T19:11:14.363
61660
2019-12-21T19:11:14.363
61655
answer