diff --git a/mirai-core-utils/src/commonMain/kotlin/File.kt b/mirai-core-utils/src/commonMain/kotlin/File.kt
index 74775a115..859355ab0 100644
--- a/mirai-core-utils/src/commonMain/kotlin/File.kt
+++ b/mirai-core-utils/src/commonMain/kotlin/File.kt
@@ -76,7 +76,7 @@ public fun MiraiFile.writeText(text: String) {
 }
 
 public fun MiraiFile.readText(): String {
-    return input().use { it.readText() }
+    return input().use { it.readAllText() }
 }
 
 public fun MiraiFile.readBytes(): ByteArray {
diff --git a/mirai-core-utils/src/commonMain/kotlin/IO.kt b/mirai-core-utils/src/commonMain/kotlin/IO.kt
index 3a9e38e20..48ad89b5f 100644
--- a/mirai-core-utils/src/commonMain/kotlin/IO.kt
+++ b/mirai-core-utils/src/commonMain/kotlin/IO.kt
@@ -167,6 +167,8 @@ public fun Input._readTLVMap(
     return map
 }
 
+public fun Input.readAllText(): String = Charsets.UTF_8.newDecoder().decode(this)
+
 public inline fun Input.readString(length: Int, charset: Charset = Charsets.UTF_8): String =
     String(this.readBytes(length), charset = charset) // stdlib
 
diff --git a/mirai-core-utils/src/mingwX64Main/kotlin/MiraiFileImpl.kt b/mirai-core-utils/src/mingwX64Main/kotlin/MiraiFileImpl.kt
index 1c09c4a82..e12bcaedf 100644
--- a/mirai-core-utils/src/mingwX64Main/kotlin/MiraiFileImpl.kt
+++ b/mirai-core-utils/src/mingwX64Main/kotlin/MiraiFileImpl.kt
@@ -9,13 +9,46 @@
 
 package net.mamoe.mirai.utils
 
+import io.ktor.utils.io.bits.*
 import io.ktor.utils.io.core.*
+import io.ktor.utils.io.errors.*
 import kotlinx.cinterop.*
-import platform.posix.PATH_MAX
-import platform.posix.fopen
-import platform.posix.getcwd
+import platform.posix.*
 import platform.windows.*
 
+private fun getFullPathName(path: String): String = memScoped {
+    try {
+        println("getFullPathName")
+        ShortArray(MAX_PATH).usePinned { pin ->
+            val len = GetFullPathNameW(path, MAX_PATH, pin.addressOf(0).reinterpret(), null).toInt()
+            if (len != 0) {
+                return pin.get().toKStringFromUtf16(len)
+            } else {
+                when (val errno = errno) {
+                    ENOTDIR -> return@memScoped path
+                    EACCES -> return@memScoped path // permission denied
+                    ENOENT -> return@memScoped path // no such file
+                    else -> throw IllegalArgumentException(
+                        "Invalid path($errno): $path",
+                        cause = PosixException.forErrno(posixFunctionName = "GetFullPathNameW()")
+                    )
+                }
+            }
+        }
+    } finally {
+        println("getFullPathName finished")
+    }
+}
+
+private fun ShortArray.toKStringFromUtf16(len: Int): String {
+    val chars = CharArray(len)
+    var index = 0
+    while (index < len) {
+        chars[index] = this[index].toInt().toChar()
+        ++index
+    }
+    return chars.concatToString()
+}
 
 internal actual class MiraiFileImpl actual constructor(
     // canonical
@@ -40,14 +73,16 @@ internal actual class MiraiFileImpl actual constructor(
         }
     }
 
-    override val absolutePath: String = kotlin.run {
-        val result = ROOT_REGEX.matchEntire(path) ?: return@run path.dropLastWhile { it.isSeparator() }
-        return@run result.groups.first()!!.value
+    override val absolutePath: String by lazy {
+        val result = ROOT_REGEX.matchEntire(this.path)
+            ?: return@lazy getFullPathName(this.path).removeSuffix(SEPARATOR.toString())
+        return@lazy result.groups.first()!!.value
     }
 
     private fun Char.isSeparator() = this == '/' || this == '\\'
 
     override val parent: MiraiFile? by lazy {
+        if (ROOT_REGEX.matchEntire(this.path) != null) return@lazy null
         val absolute = absolutePath
         val p = absolute.substringBeforeLast(SEPARATOR, "")
         if (p.isEmpty()) {
@@ -66,41 +101,63 @@ internal actual class MiraiFileImpl actual constructor(
 
     override val name: String
         get() = if (absolutePath.matches(ROOT_REGEX)) absolutePath
-        else absolutePath.substringAfterLast('/')
+        else absolutePath.substringAfterLast(SEPARATOR)
 
     init {
-        checkName(absolutePath.substringAfterLast('/')) // do not check drive letter
+        checkName(absolutePath.substringAfterLast(SEPARATOR)) // do not check drive letter
     }
 
     private fun checkName(name: String) {
-        name.substringAfterLast('/').forEach { c ->
+        name.substringAfterLast(SEPARATOR).forEach { c ->
             if (c in """\/:?*"><|""") {
                 throw IllegalArgumentException("'${name}' contains illegal character '$c'.")
             }
         }
 
-        memScoped {
-            val b = alloc<WINBOOLVar>()
-            CheckNameLegalDOS8Dot3A(absolutePath, nullPtr(), 0, nullPtr(), b.ptr)
-            if (b.value != 1) {
-                throw IllegalArgumentException("'${name}' contains illegal character.")
-            }
-        }
+//        memScoped {
+//            val b = alloc<WINBOOLVar>()
+//            CheckNameLegalDOS8Dot3A(absolutePath, nullPtr(), 0, nullPtr(), b.ptr)
+//            if (b.value != 1) {
+//                throw IllegalArgumentException("'${name}' contains illegal character.")
+//            }
+//        }
     }
 
     override val length: Long
         get() = useStat { it.st_size.convert() } ?: 0
+//            memScoped {
+//                val handle = CreateFileW(
+//                    absolutePath,
+//                    GENERIC_READ,
+//                    FILE_SHARE_READ,
+//                    null,
+//                    OPEN_EXISTING,
+//                    FILE_ATTRIBUTE_NORMAL,
+//                    null
+//                ) ?: return@memScoped 0
+//                val length = alloc<DWORDVar>()
+//                if (GetFileSize(handle, length.ptr) == INVALID_FILE_SIZE) {
+//                    if (GetLastError() == NO_ERROR.toUInt()) {
+//                        return INVALID_FILE_SIZE.convert()
+//                    }
+//                    throw PosixException.forErrno(posixFunctionName = "GetFileSize()").wrapIO()
+//                }
+//                if (CloseHandle(handle) == FALSE) {
+//                    throw PosixException.forErrno(posixFunctionName = "CloseHandle()").wrapIO()
+//                }
+//                length.value.convert()
+//            }
 
 
     override val isFile: Boolean
-        get() = getFileAttributes() flag FILE_ATTRIBUTE_NORMAL
+        get() = useStat { it.st_mode.convert<UInt>() flag S_IFREG } ?: false
 
     override val isDirectory: Boolean
-        get() = getFileAttributes() flag FILE_ATTRIBUTE_DIRECTORY
+        get() = useStat { it.st_mode.convert<UInt>() flag S_IFDIR } ?: false
 
     override fun exists(): Boolean = getFileAttributes() != INVALID_FILE_ATTRIBUTES
 
-    private fun getFileAttributes(): DWORD = memScoped { GetFileAttributesA(absolutePath) }
+    private fun getFileAttributes(): DWORD = memScoped { GetFileAttributesW(absolutePath) }
 
     override fun resolve(path: String): MiraiFile {
         when (path) {
@@ -121,54 +178,177 @@ internal actual class MiraiFileImpl actual constructor(
     }
 
     override fun createNewFile(): Boolean {
-        memScoped {
-            // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
-            val handle = CreateFileA(
-                absolutePath,
-                GENERIC_READ,
-                FILE_SHARE_WRITE,
-                nullPtr(),
-                CREATE_NEW,
-                FILE_ATTRIBUTE_NORMAL,
-                nullPtr()
-            )
-            if (handle == NULL) return false
-            CloseHandle(handle)
-            return true
+        // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+        val handle = CreateFileW(
+            absolutePath,
+            GENERIC_READ,
+            FILE_SHARE_DELETE,
+            null,
+            CREATE_NEW,
+            FILE_ATTRIBUTE_NORMAL,
+            null
+        )
+        if (handle == null || handle == INVALID_HANDLE_VALUE) {
+            return false
         }
+        if (CloseHandle(handle) == FALSE) {
+            throw PosixException.forErrno(posixFunctionName = "CloseHandle()").wrapIO()
+        }
+        return true
     }
 
     override fun delete(): Boolean {
         return if (isFile) {
-            DeleteFileA(absolutePath) == 0
+            DeleteFileW(absolutePath) != 0
         } else {
-            RemoveDirectoryA(absolutePath) == 0
+            RemoveDirectoryW(absolutePath) != 0
         }
     }
 
     override fun mkdir(): Boolean {
         memScoped {
             val v = alloc<_SECURITY_ATTRIBUTES>()
-            return CreateDirectoryA(absolutePath, v.ptr) == 0
+            return CreateDirectoryW(absolutePath, v.ptr) != 0
         }
     }
 
     override fun mkdirs(): Boolean {
-        if (this.parent?.mkdirs() == false) {
-            return false
-        }
+        this.parent?.mkdirs()
         return mkdir()
     }
 
     override fun input(): Input {
-        val handle = fopen(absolutePath, "r")
-        if (handle == NULL) throw IllegalStateException("Failed to open file '$absolutePath'")
-        return PosixInputForFile(handle!!)
+//        println(absolutePath)
+//        val handle2 = fopen(absolutePath, "rb") ?:throw IOException(
+//            "Failed to open file '$absolutePath'",
+//            PosixException.forErrno(posixFunctionName = "fopen()")
+//        )
+//        return PosixInputForFile(handle2)
+        // Will get I/O operation failed due to posix error code 2
+
+        val handle = CreateFileW(
+            absolutePath,
+            GENERIC_READ,
+            FILE_SHARE_DELETE,
+            null,
+            OPEN_EXISTING,
+            FILE_ATTRIBUTE_NORMAL,
+            null
+        )
+        if (handle == null || handle == INVALID_HANDLE_VALUE) throw IOException(
+            "Failed to open file '$absolutePath'",
+            PosixException.forErrno(posixFunctionName = "CreateFileW()")
+        )
+        return WindowsFileInput(handle)
     }
 
     override fun output(): Output {
-        val handle = fopen(absolutePath, "w")
-        if (handle == NULL) throw IllegalStateException("Failed to open file '$absolutePath'")
-        return PosixFileInstanceOutput(handle!!)
+//        val handle2 = fopen(absolutePath, "wb")
+//            ?: throw IOException(
+//                "Failed to open file '$absolutePath'",
+//                PosixException.forErrno(posixFunctionName = "fopen()")
+//            )
+//        return PosixFileInstanceOutput(handle)
+//
+        println(absolutePath)
+        val handle = CreateFileW(
+            absolutePath,
+            GENERIC_WRITE,
+            FILE_SHARE_DELETE,
+            null,
+            (if (exists()) TRUNCATE_EXISTING else CREATE_NEW).toUInt(),
+            FILE_ATTRIBUTE_NORMAL,
+            null
+        )
+        if (handle == null || handle == INVALID_HANDLE_VALUE) throw IOException(
+            "Failed to open file '$absolutePath'",
+            PosixException.forErrno(posixFunctionName = "CreateFileW()")
+        )
+        return WindowsFileOutput(handle)
     }
-}
\ No newline at end of file
+
+    override fun hashCode(): Int {
+        return this.path.hashCode()
+    }
+
+    override fun equals(other: Any?): Boolean {
+        if (other == null) return false
+        if (!isSameType(this, other)) return false
+        return this.path == other.path
+    }
+
+    override fun toString(): String {
+        return "MiraiFileImpl($path)"
+    }
+}
+
+
+internal class WindowsFileInput(private val file: HANDLE) : Input() {
+    private var closed = false
+
+    override fun fill(destination: Memory, offset: Int, length: Int): Int {
+        if (file == INVALID_HANDLE_VALUE) return 0
+
+        println("fill: ${destination.pointer}, $offset, $length")
+        memScoped {
+            val n = alloc<DWORDVar>()
+            if (ReadFile(file, destination.pointer + offset, length.convert(), n.ptr, null) == FALSE) {
+                println("ERR! LastErr= ${GetLastError()}")
+                throw PosixException.forErrno(posixFunctionName = "ReadFile()").wrapIO()
+            }
+
+            println("LastErr= ${GetLastError()}")
+            println("${n.value}, ${n.value.convert<UInt>().toInt()}")
+            return n.value.convert<UInt>().toInt()
+        }
+    }
+
+    override fun closeSource() {
+        println("closing")
+        if (closed) return
+        closed = true
+
+        if (file != INVALID_HANDLE_VALUE) {
+            if (CloseHandle(file) == FALSE) {
+                throw PosixException.forErrno(posixFunctionName = "CloseHandle()").wrapIO()
+            }
+        }
+    }
+}
+
+@Suppress("DEPRECATION")
+internal class WindowsFileOutput(private val file: HANDLE) : Output() {
+    private var closed = false
+
+    override fun flush(source: Memory, offset: Int, length: Int) {
+        val end = offset + length
+        var currentOffset = offset
+
+        memScoped {
+            val written = alloc<UIntVar>()
+            while (currentOffset < end) {
+                val result = WriteFile(
+                    file,
+                    source.pointer + currentOffset.convert(),
+                    (end - currentOffset).convert(),
+                    written.ptr,
+                    null
+                ).convert<Int>()
+                if (result == FALSE) {
+                    throw PosixException.forErrno(posixFunctionName = "WriteFile()").wrapIO()
+                }
+                currentOffset += written.value.toInt()
+            }
+
+        }
+    }
+
+    override fun closeDestination() {
+        if (closed) return
+        closed = true
+
+        if (CloseHandle(file) == FALSE) {
+            throw PosixException.forErrno(posixFunctionName = "CloseHandle()").wrapIO()
+        }
+    }
+}
diff --git a/mirai-core-utils/src/mingwX64Test/kotlin/MiraiFileImplTest.kt b/mirai-core-utils/src/mingwX64Test/kotlin/MiraiFileImplTest.kt
index f8bfbee5d..9562dee6a 100644
--- a/mirai-core-utils/src/mingwX64Test/kotlin/MiraiFileImplTest.kt
+++ b/mirai-core-utils/src/mingwX64Test/kotlin/MiraiFileImplTest.kt
@@ -16,20 +16,30 @@ import kotlin.test.assertEquals
 
 internal class WindowsMiraiFileImplTest : AbstractNativeMiraiFileImplTest() {
     private val rand = Random.nextInt().absoluteValue
-    override val baseTempDir: MiraiFile = MiraiFile.create("mirai_unit_tests")
-    override val tempPath = "mirai_unit_tests/temp$rand"
+    override val baseTempDir: MiraiFile = MiraiFile.create("C:\\mirai_unit_tests")
+    override val tempPath = "C:\\mirai_unit_tests\\temp$rand"
 
     @Test
     override fun parent() {
-        assertEquals("C:/Users/Shared/mirai_test", tempDir.parent!!.absolutePath)
+        assertEquals("C:\\mirai_unit_tests", tempDir.parent!!.absolutePath)
         super.parent()
     }
 
+    override fun `canonical paths for non-canonical input`() {
+        super.`canonical paths for non-canonical input`()
+
+        // extra /sss/..
+        MiraiFile.create("$tempPath/sss/..").resolve("test").let {
+            assertPathEquals("${tempPath}/test", it.path) // Windows resolves always
+            assertPathEquals("${tempPath}/test", it.absolutePath)
+        }
+    }
+
     @Test
     override fun `resolve absolute`() {
-        MiraiFile.create("$tempPath/").resolve("C:/Users").let {
-            assertEquals("C:/Users", it.path)
-            assertEquals("C:/Users", it.absolutePath)
+        MiraiFile.create("$tempPath/").resolve("C:\\mirai_unit_tests").let {
+            assertEquals("C:\\mirai_unit_tests", it.path)
+            assertEquals("C:\\mirai_unit_tests", it.absolutePath)
         }
     }
 }
\ No newline at end of file
diff --git a/mirai-core-utils/src/nativeTest/kotlin/AbstractNativeMiraiFileImplTest.kt b/mirai-core-utils/src/nativeTest/kotlin/AbstractNativeMiraiFileImplTest.kt
index 88515a7e2..2c94a6236 100644
--- a/mirai-core-utils/src/nativeTest/kotlin/AbstractNativeMiraiFileImplTest.kt
+++ b/mirai-core-utils/src/nativeTest/kotlin/AbstractNativeMiraiFileImplTest.kt
@@ -24,7 +24,7 @@ internal abstract class AbstractNativeMiraiFileImplTest {
     @AfterTest
     fun afterTest() {
         println("Cleaning up...")
-        baseTempDir.deleteRecursively()
+        println("deleteRecursively:" + baseTempDir.deleteRecursively())
     }
 
     @BeforeTest
@@ -35,8 +35,8 @@ internal abstract class AbstractNativeMiraiFileImplTest {
 
     @Test
     fun `canonical paths for canonical input`() {
-        assertEquals(tempPath, tempDir.path)
-        assertEquals(tempPath, tempDir.absolutePath)
+        assertPathEquals(tempPath, tempDir.path)
+        assertPathEquals(tempPath, tempDir.absolutePath)
     }
 
     @Test
@@ -46,31 +46,26 @@ internal abstract class AbstractNativeMiraiFileImplTest {
     }
 
     @Test
-    fun `canonical paths for non-canonical input`() {
+    open fun `canonical paths for non-canonical input`() {
         // extra /
         MiraiFile.create("$tempPath/").resolve("test").let {
-            assertEquals("${tempPath}/test", it.path)
-            assertEquals("${tempPath}/test", it.absolutePath)
+            assertPathEquals("${tempPath}/test", it.path)
+            assertPathEquals("${tempPath}/test", it.absolutePath)
         }
         // extra //
         MiraiFile.create("$tempPath//").resolve("test").let {
-            assertEquals("${tempPath}/test", it.path)
-            assertEquals("${tempPath}/test", it.absolutePath)
+            assertPathEquals("${tempPath}/test", it.path)
+            assertPathEquals("${tempPath}/test", it.absolutePath)
         }
         // extra /.
         MiraiFile.create("$tempPath/.").resolve("test").let {
-            assertEquals("${tempPath}/test", it.path)
-            assertEquals("${tempPath}/test", it.absolutePath)
+            assertPathEquals("${tempPath}/test", it.path)
+            assertPathEquals("${tempPath}/test", it.absolutePath)
         }
         // extra /./.
         MiraiFile.create("$tempPath/./.").resolve("test").let {
-            assertEquals("${tempPath}/test", it.path)
-            assertEquals("${tempPath}/test", it.absolutePath)
-        }
-        // extra /sss/..
-        MiraiFile.create("$tempPath/sss/..").resolve("test").let {
-            assertEquals("${tempPath}/sss/../test", it.path) // because file is not found
-            assertEquals("${tempPath}/sss/../test", it.absolutePath)
+            assertPathEquals("${tempPath}/test", it.path)
+            assertPathEquals("${tempPath}/test", it.absolutePath)
         }
     }
 
@@ -90,7 +85,7 @@ internal abstract class AbstractNativeMiraiFileImplTest {
         assertFalse { tempDir.resolve("not_existing_dir").exists() }
         assertEquals(0L, tempDir.resolve("not_existing_dir").length)
         assertTrue { tempDir.resolve("not_existing_dir").mkdir() }
-        assertNotEquals(0L, tempDir.resolve("not_existing_dir").length)
+//        assertNotEquals(0L, tempDir.resolve("not_existing_dir").length) // length is platform-dependent, on Windows it is 0 but on unix it is not
         assertTrue { tempDir.resolve("not_existing_dir").exists() }
     }
 
@@ -98,20 +93,27 @@ internal abstract class AbstractNativeMiraiFileImplTest {
     fun `isFile isDirectory`() {
         assertTrue { tempDir.exists() }
 
+        println("1")
         assertFalse { tempDir.resolve("not_existing_file.txt").exists() }
         assertEquals(false, tempDir.resolve("not_existing_file.txt").isFile)
+        println("1")
         assertEquals(false, tempDir.resolve("not_existing_file.txt").isDirectory)
+        println("1")
         assertTrue { tempDir.resolve("not_existing_file.txt").createNewFile() }
         assertEquals(true, tempDir.resolve("not_existing_file.txt").isFile)
         assertEquals(false, tempDir.resolve("not_existing_file.txt").isDirectory)
+        println("1")
         assertTrue { tempDir.resolve("not_existing_file.txt").exists() }
 
+        println("1")
         assertFalse { tempDir.resolve("not_existing_dir").exists() }
         assertEquals(false, tempDir.resolve("not_existing_dir").isFile)
         assertEquals(false, tempDir.resolve("not_existing_dir").isDirectory)
+        println("1")
         assertTrue { tempDir.resolve("not_existing_dir").mkdir() }
         assertEquals(false, tempDir.resolve("not_existing_dir").isFile)
         assertEquals(true, tempDir.resolve("not_existing_dir").isDirectory)
+        println("1")
         assertTrue { tempDir.resolve("not_existing_dir").exists() }
     }
 
@@ -134,7 +136,7 @@ internal abstract class AbstractNativeMiraiFileImplTest {
 
     @Test
     fun readText() {
-        tempDir.resolve("readText1.txt").let { file ->
+        tempDir.resolve("readText2.txt").let { file ->
             assertTrue { !file.exists() }
             assertFailsWith<IOException> { file.readText() }
 
@@ -143,4 +145,39 @@ internal abstract class AbstractNativeMiraiFileImplTest {
             assertEquals(text, file.readText())
         }
     }
+
+    private val bigText = "some text".repeat(10000)
+
+    @Test
+    fun writeBigText() {
+        // new file
+        tempDir.resolve("writeText3.txt").let { file ->
+            file.writeText(bigText)
+            assertEquals(bigText.length, file.length.toInt())
+        }
+
+        // override
+        tempDir.resolve("writeText4.txt").let { file ->
+            file.writeText(bigText)
+            assertEquals(bigText.length, file.length.toInt())
+        }
+    }
+
+    @Test
+    fun readBigText() {
+        tempDir.resolve("readText4.txt").let { file ->
+            assertTrue { !file.exists() }
+            assertFailsWith<IOException> { file.readText() }
+
+            file.writeText(bigText)
+            println("reading text")
+            val read = file.readText()
+            assertEquals(bigText.length, read.length)
+            assertEquals(bigText, read)
+        }
+    }
+
+    protected fun assertPathEquals(expected: String, actual: String, message: String? = null) {
+        asserter.assertEquals(message, expected.replace("\\", "/"), actual.replace("\\", "/"))
+    }
 }
\ No newline at end of file
diff --git a/mirai-core-utils/src/unixTest/kotlin/UnixMiraiFileImplTest.kt b/mirai-core-utils/src/unixTest/kotlin/UnixMiraiFileImplTest.kt
index 91d7751c8..05d17c5e0 100644
--- a/mirai-core-utils/src/unixTest/kotlin/UnixMiraiFileImplTest.kt
+++ b/mirai-core-utils/src/unixTest/kotlin/UnixMiraiFileImplTest.kt
@@ -28,6 +28,16 @@ internal class UnixMiraiFileImplTest : AbstractNativeMiraiFileImplTest() {
         super.parent()
     }
 
+    override fun `canonical paths for non-canonical input`() {
+        super.`canonical paths for non-canonical input`()
+
+        // extra /sss/..
+        MiraiFile.create("$tempPath/sss/..").resolve("test").let {
+            assertPathEquals("${tempPath}/sss/../test", it.path) // because file is not found
+            assertPathEquals("${tempPath}/sss/../test", it.absolutePath)
+        }
+    }
+
     @Test
     override fun `resolve absolute`() {
         MiraiFile.create("$tempPath/").resolve("/Users").let {