0

I recenlty desired a bit of python code that would allow me to output to the console and a logfile with the same print statement. After googleing I found this website which offered an excellent solution. However, I would like to be able to flush the output buffer after each write in order to see it in the log file. How would I go about adding it into this class?

I have tried to following setups...

class output_file(object):
  def __init__(self, stdout, filename):
    silentremove(filename)
    self.stdout = stdout
    self.logfile = open(filename, "a")

def write(self, text):
    self.stdout.write(text)
    self.logfile.write(text)
    sys.stdout.flush()

  def flush(self):
    sys.stdout.flush()

  def close(self):
    self.stdout.close()
    self.logfile.close()

This was had a cyclic error which resulted in the flush function calling itself.

class output_file(object):
  def __init__(self, stdout, filename):
    silentremove(filename)
    self.stdout = stdout
    self.logfile = open(filename, "a")

  def write(self, text):
    self.stdout.write(text)
    self.logfile.write(text)
    self.stdout.flush()

  def flush(self):
    sys.stdout.flush()

  def close(self):
    self.stdout.close()
    self.logfile.close()

This didn't flush it at all.

Marmstrong
  • 1,686
  • 7
  • 30
  • 54
  • 4
    Not answering the question but you may want to look at the logging module. To do what you want to do, you can define two handlers (One for console and one for file) for the same logger – RedBaron Feb 24 '14 at 11:15
  • @RedBaron This is exactly what I was looking for originally. If you submit it as an answer I will accept it. – Marmstrong Feb 24 '14 at 14:28
  • Technically it wasn't an answer to your question so won't be appropriate for me to post it. For future visitors, you can post an epilogue to your question explaining how `logging` helped you overcome your original problem (which led to this question) – RedBaron Feb 25 '14 at 04:21

1 Answers1

4

The following reopens sys.stdout in unbuffered mode. Each stdout.write and print will be automatically flushed (i.e. printed to stdout) afterwards.

import sys
import os

# Flush STDOUT continuously
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

The third argument of os.fdopen is the buffering argument, 0 is unbuffered, 1 is line buffered and >1 will result in a buffer of (approximately) that size (in bytes), <0 will use the systems default.

UPDATE

With Python 3 unbuffered text is not allowed, i.e. the following

sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

Will result in the error

ValueError: Can't have unbuffered text I/O

To use unbuffered I/O in python3, bytes can be used, i.e.

sys.stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0)

Will work fine in python3.

Gio
  • 3,242
  • 1
  • 25
  • 53