Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python read file non blocking on windows

I have a programm on windows (Win7) that writes to a txt file every x seconds. Now I have a python script that reads this txt File every x seconds. When the python script reads the File and at the same time the other Program wants to write to that file - The writing program crashes (and displays permission error). Since I cant modify the way the Program writes to the txt file, I have to try to open the txt File without blocking the writing program. Does someone know what I could do in this situation (reading without blocking) I would be very happy for every tip on this topic!

The code for the Program that tries to read the File goes something like this:

    with codecs.open(datapath, "r", 'utf-16') as raw_data:

         raw_data_x = raw_data.readlines()

I have to open the File with "codecs" because its in unicode.

like image 770
Py42 Avatar asked Mar 22 '16 19:03

Py42


1 Answers

After a long time, I managed to create a function that does it for you in ctypes. Keep in mind this will only work if the process didn't acquire "Exclusive" access. If it did, you're out of luck and will need to use a shadow copy service like shown here or implemented here.
Anyway, here you go:

import ctypes
from ctypes import wintypes
import os
import msvcrt

GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000

OPEN_EXISTING = 3
OPEN_ALWAYS = 4

ACCESS_MODES = {
    "r": GENERIC_READ,
    "w": GENERIC_WRITE,
    "r+": (GENERIC_READ|GENERIC_WRITE)
}

OPEN_MODES = {
    "r": OPEN_EXISTING,
    "w": OPEN_ALWAYS,
    "r+": OPEN_ALWAYS,
}


def open_file_nonblocking(filename, access):
    # Removes the b for binary access.
    internal_access = access.replace("b", "")
    access_mode = ACCESS_MODES[internal_access]
    open_mode = OPEN_MODES[internal_access]
    handle = wintypes.HANDLE(ctypes.windll.kernel32.CreateFileW(
        wintypes.LPWSTR(filename),
        wintypes.DWORD(access_mode),
        wintypes.DWORD(2|1),  # File share read and write
        ctypes.c_void_p(0),
        wintypes.DWORD(open_mode),
        wintypes.DWORD(0),
        wintypes.HANDLE(0)
    ))

    try:
        fd = msvcrt.open_osfhandle(handle.value, 0)
    except OverflowError as exc:
        # Python 3.X
        raise OSError("Failed to open file.") from None
        # Python 2
        # raise OSError("Failed to open file.")

    return os.fdopen(fd, access)

The function opens the file while sharing the read and write handle allowing multiple access. It then converts the handle to a normal python file object.
Make sure to close the file when you finish.

like image 86
Bharel Avatar answered Sep 24 '22 18:09

Bharel