Linux File、File Directory IO Operation Summary(undone)
目录
. 引言
. Linux下文件操作API
. Linux下文件目录操作API
. Linux下的其他设备操作API
1. 引言
Linux支持多种文件系统,如ext、ext2、minix、iso9660、msdos、fat、vfat、nfs等。在这些具体文件系统的上层,Linux提供了虚拟文件系统(VFS)来统一它们的行为,虚拟文件系统为不同的文件系统与内核的通信提供了一致的接口
Linux的文件编程有两种途径: 基于Linux系统调用、基于C库函数。这两种编程所涉及到文件操作有新建、打开、读写和关闭,对随机文件还可以定位
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeAAAAD8CAIAAAAg1eCWAAAgAElEQVR4nO2d23qjuhKEhQDbycx+//ecZGLOvS9qUastnFlxBpDj1H/hD2PMQYdSq9USIYhvSVVVIYSiKMqy5FexBUxbbNR1nfV2hBD3TVEUwQnH8XgMIRwOh5z39KBAjuu6jjEGqbMQ4oN4q7nvexMbME1T27b8iv6KEEL8CRh0MKVDCOM4TtOUUcgelXEczYxpG2NkmgshxBW8MxTbZjYMwyRWBf0SfA7DYGZB7n4hxH/y9PTE7aIomqbJZmQ+NK+vr9iYpmkYBvmghRAfAt1t+DrMdcPFuiBh8Rlm55IQQrwLPaHYWF2VODIG27zrOoiUbwbQ9x/HEY5aDxwCxBv40zR1XedVz/8dFzKz8/nMU/EA3lVyft7Gcv9fkjR7WfNcCPFF2FSgoUqMDIHqUf7O53Pf94ly9X0PJaXC4hh/KnjJk6tQfPFHXGIZlJI0DOM4tm3bdR0vxwPWDWiRQAshbmZTgYb8mVnTNLSdzWwYBm+iDsPgVZXAXsZf3t7e8CuNXyoyNpqm8aeFvPKiTdPwMNjIS08OFdnHw62FBFoIcTNbuzjsUknpx8BYmTlZ5P5pmjiklpynbVtKPHa2bes9GzCusQfq3HWd130KpY97u9o80KZeBQm0EOJmtraguU35o7+i6zpcEVYtnBv81ziOfjYHhzExpJlYuzjG5gkgDO7mpaHjjCDkk9KpjYvibLKghRB3waYCTSMU8jcMA8cDsb/ve3/RcDmVMfmJSleW5dvbm7lYCHPxxeYiJXgDOBKhx6fTiY8fYyzLsixLtBBm9vv3b5xBPmghRGa2dnFQ6WCWDsPAS8cYoY+8OjSUbpAw63XbtnVdQ4Jp/1Ll67qmf7ksSzhPpmmq69rMzuczNL3ve+h10zRefCni9J/YZbjIWungv+6f0UKIr8cOFjSNU+yJMZpzI3ADYXPmhhDho4BPmf4KM4PaTtO0vPnkoSi+RVHweHzSf1KWpfc+L8M5VkECLYS4ma3D7BinTIUKIUzTVFWVOTc0FZlDfDjSuyMAp6SDvu9xKi/0/Il7qqry44H+Huj7BhJoIcS9sEMUB4Fi8irJhvdHn8/nruuKoqB0htmt0XXd6XSiCwI+aEhtuJyeBxuZ3pIkejoslu6Ti0MIcV/sEMUBLzDtYro4TqcTpoqEEDjE56eucD8cI1RY75TAzXtxxwntMhgDe5KH5bYGCYUQ98jWLo6lKRoWFnRRFFRV0Pf9y8sLXiAQQqiqKllA2ebxRh8zRxO4rmtGUuMGgnOkmNn5fA5zvAe82wqzE0LcHTu4OGA+c+gvhMBgZO+brusaR3Iqih8YDLM1DV3mTnxi1jhOwkdDFIeZtW0bY+QEQkg24j00UUUIcb9sLdBcq4g6BX8x1fDt7Y1hyxQy2LCYkAJJ5b31fQ/h5vTxsix5cs5bwZH4Ok3T6XSij8VfzvsxNNVbCHFf7DNIyPnWYR6aozlMwbLLgLzkZo7HI5c0qusaE1XM7O3tLcboAzZsto6xZxiGGCPbCS7V5O9EiyUJIe6RHQTa+wrCPFiHcAt4luFrxnZd195e5uTvEAItX/6KPRh1RMSeh5MMMQZoTnN5kmThU9Nyo0KI+2HPMLvvjARaCHEzEuh9kEALIW5GAr0PEmghxM1IoPdBAi2EuBkJ9D5IoIUQNyOB3gcJtBDiZiTQ+yCBFkLcjAR6HyTQQoib4eIVfnFOsTqcrYMpMH5ZVCGEeJfD4cCNdVcIEh6mbdd1THMhhHgXTrmmi2OLpYIEZplj/WszC/OrYYQQ4jq+o431MZJll8Va4H24/kUBEmghxH+TyLQXEbEWaPnkehZC3ADeyso3+4XZ3SFWBAmLRMbn8/NzzlwXQtw/XO0zxlgURXADhmJdfv78iY2iKLiwatY7EkJ8KaDRhVwcW6JEFkIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBCfIcaIjaIo+CnWJUnVuq6XO4UQ4gJoBDU6xhhjLMTahFmUkbwZc1wI8ZU4HA7h0pqjXou1KFzvBMkLvRZCiHepqirMhnNVVTHGHz9+cI9YixACEtZzPB73z3EhxFfidDole8qyzHInDwy9HEVRlGVZlmVUN0UI8RGqqoJwSDU2Asmb7Ml1M0KIr4FXDWybWdd1JlZlGIZkO8gNLYT4CPBEF0VR13XTNPl07MFByzdNU9d1GJsVQog/wb42NnKL2D9M0zSOI7aHYZimyczGccQGDsBG27b+X2bW9z3+tbRbM8IbBlnzXAjxRbgrgU68K13XTdPU9z3FOhFf7B+GARvjOL6+vvLv4zhC0/0ZciGBFkLczF0JtM0W8fl8xldvR2PbO2Goeon+tm27tLXz+tYl0EKIm7krgfaOCCh127Z0YgzDwO2+770TwysyrGxY3zZ7SLwnJAsSaCHEzdyVQAOaulTVPzso8CuMbuggxf1+IlIk0EKIm7k3gYa2elOa6gyHMgcMKb7jOMJqBl6jPXnHCSXQQoibuSuB9t4Mc35nbwj74cGErusYysZPHO8VPAsSaCHEzdyVQJuZj7gI84IVNitaURT+1zBPg8Q293PSDT4Z7LH/4xAJtBDiZu5KoP1AH1TV31JRFDiABnVVVdwuigLH8yRY9SJxgORCAi2EuJm7EmhzAXZm1rZtXdfn8xkqHEKg1HLCNA/GnsPhQJ/GMAw8ILtGS6CFEDdzbwINvzP9GDFGbPR9X9c1ttu2heCGELxSY+fVB8k+hV0CLYS4mXsTaAJTum1b+i7atk1mb4cQyrLEW0vgyqAOYnnrpmn6vvcjh7mQQAshbuauBBqG8+vrKza8mXw4HHgYV+qAfd33fVi4MpqmGYbhdDrZtZC7/ZFACyFu5q4E2nuKYfaO4wgVDiFM0zQMAycKmllVVX4ueNu2ySP4r3mX45BACyFu5q4E2px/GdvexZzM2B7HMYTw9vbGrzYLH8Oog/NNy8UhhPhi3JtAE28al2VJIYbaQp1jjIfDoWkaLjSKR0gio/GTBFoI8cW4W4F+MCTQQoibkUDvgwRaCHEzEuh9kEALIW5GAr0PEmghxM1IoPdBAi2EuBkJ9D5IoIUQNyOB3gcJtBDiZiTQ+yCBFkLcTF3X2MAi93nnQz8wXLcasxxjjFmzXQjxRTgcDty4n7esPh5M267rmOZCCPEuMOWwaGcIwe5j7bfHAzPU/ZtiqqrKnPdCiHvGd7SLoogxwtEhVifG6F+fGCTQQoiPkMi0FxGxFmj55HoWQtzA6XQKs3DApuM7SsRaIGGRyPh8fn7OmetCiPsHZt3xeIwxFkUR3IChWJefP39ioygKJDvjZ4QQ4r+BRhdycWyJElkIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgjxDSnLEhtFUVRVlfdmHpXD4ZDsqes6y52EEJjLRVHga4wx1808NlVVoX4laf614D2rnGxNWZYU5H++V1U1DIOZDcPQdZ2JDRiGYRgG1NKqqpZ6vTO4ExaFvu/7vs+dSA9I27ZmxmoVY7yofveNb0tQYmOMWZPzMZmmidsoMOM4XuTEOI5mhiqqiro6zAAYIJTpXWvbgtPpFGNEJcybPo9N0zQsAHlz/FYSqx99PhhzYkXYfqOc4Ou/DfnhcPAHiY1o2zZc83XsT1EU3sFS1/X5fM6dPA/INE0wiEDbtqfTKWO+f4Lj8chWPIRwOp0ypucD0zTNOI5syM/n878ZEGYDCt3wfDf5sLRti4oaQiiKAm6lTDXuH+h9xtfcKfSwoNbR+sma5zfjvTHPz8/Y8P1xsQpedX///o2Nf/OgKAoUICS9NHoLhmGYpgl2K8Qxoy8St4GsDyEcj0f4uMS6wFvItO26jmn+JYBHDjYcvtZ1nTVFHxOUkKZp8HUYBvS2QwihLMvD4TBNEwqTHB1bMAzDOI5t29K3kN3RgVpHC1oDDxsB3xENoC80QghQXGOMh8MBTYuKyhawhHRdB0P5opONg9R52Qh2SpDaKOh3YknBSjJn6IktQPKGLxWp5ouovGHb4ase2r9pmi7yAL+tLtA4IS9POx372RQzyM/fwDRN+KMf2aTSeT8MDvOBKPyVY19Js4+D/QDO1uApluU+F7yHjaI4/MB03/fM2aRIINN9DtqlZ6BtW18M/MnpkVsWM7vM3HEcE8cdi6I/G1grBfzNkKx5/rfsH/CDXGMJ4U6fU8jHl5cXu2Zk+GLAMonT8id0cHmYL0i+7DEUlXq11mNe5Uqib1E6397ezCXB8/Nz27a40DRNdH/7hDifz0w72h3+tEyapmmQZP4A/No0DTaSM4zj2HUdwzlxezvwrQSa7SLy0ZcrZgeD7quqskvN9cmVnNlrPbW7KAp/8r7vWccgzcfjEZeYpmkYhqIoeKS/NzgB1+3CS6A/R5h9KdBi7xriMb9+/cLGMAxPT082S6oflWUJZLbiDCii4zh6w87mcYJhGJLjk/G5Hfw8VxJ9BxdHmEeBUVvKskzMWEYKxxgRrY1/IcV5cNd1SQsWQoD4ck/TNPja9/3xeByGgU8Kgd5zUPRbCbTNDaHNWeYfGQdAVcNcHpgLKBhLL1BRFGxNk45U13Vh9tJM0+QHW7ARQoAu434QV+qNppeXF99RWxEJ9OcYxzHGyG4Nr3s8Hvu+ZzbR/gtu1B1+c3825MLr6yu+lmVpzhxM2nWIQwgBUW0oNixUOGYH0biS6KsLtDeL8MB4eNQoaDEiQ71i0rylI4bjyD9//kSWMBvoGnt6esLIG/KJVpWZ1XWNBMWTUqmX9t12fDeBhonBLg5luu97Hwvsk8I7IsLcMPO/qFT4ykynP/fnz5/Y4FgWjGWMhie9KO5BD8873Fb3ekmgPwF0g9eibvid3tuAyk7DOczVHFOEcPNVVSXFhiFM+Dv74igDyyua64TZ9p3vK4m+hVSxyh2Px+U4Q5g7MmwS6X8YxxFR8Uhi3/mlZ8pm3cdPCJPwjRu6NjFGH+UW5lYBd7JP4Mp3E2hzCUtbla2md/8xZ71jOjgxTTbM+ZS5Ez2q4PrFPBjH9H2P5316esIjw462RQFYtzxIoD+H95IdDgdWapZbu/SDVVXFqQb+PL6kJT+FuWAklgGbc7+ICjRkedrtuJLoWwg0XcwhhL7vUSuCs3y9PcU7w6/sVsBNac71g2Rl36dtWxwMCeDQE+QewZvoMSUVeze+lUCz+HKwAQWAPSq0o/gaY/TzOOq6prHDqMS6rnnDvp6Ed6qcmY3jCFGG6R1mHwgqKu6w73tsXB2mXgUJ9CcIIZRlWdf129sbu792OVro1RkzNp+enoITDU674woWvleNqXpLNykFyuZSES5jnJqm4SU25UqibyHQSVMTLvsLOICtJXso0zTBrcE+7NVRApstIyZfuIzTxBQMn9yoohBreqhXf+ol30qgQSJ/aClDCBh7MLOiKM7nM/un+NevX7+maaIf0GbPsu+HmrNzg+sGVVXlY/7ruu77Hq27d1tjzDCpnH6i7YpIoD9NcBZbErZvl+N+ZlYUBS3ocCkyzAKOVeDvmP/hpcNflAUM5t2yX7W1EX0l0VcvoOxv+j5pmP2DNlcS77PHzfCu6GPyIS/JGJHPSF4aVRS1DlWUksRsxsa6j/we31CgAQbKkdR0CLLrU9e17wbhL8HZLNhmsHaSnsMwlGWJvMaosi2GcXg5Dk4kD87RIdr7Kz6+BPpzwPAyZ/leDeyB+cWwHIbf8Z7NhWpACmBZxxip79SWruvgTsE5QZhLTl3X3uDYmiuJvlH/zrdRYW6mcF2uvsjbgJSP44iGC4O5SB2e1nd5qNEwsrhYnz8yuPqP3IJtZZdD+Zvy3QTaJyx6SAzbYN8IuolqYHPQW2JQe81l9TMnpn3fl2WJ+oydfvU4/JrUKBgEe/acSLb8XoPdBJpdLrvU5eBcWOb0BBrCUAJ21GzR5ULnDONS/lqkqiq6T821E/tzJdG3c8BhMN0W1m5iAnspx/JOSbCd90D5lEVsAJIVcoAxVlTguq5pUNtiuGCf6SrfU6B94GOYMxFBpsgvm7tHPKxpGj/JletWIxNZopChzDuOUgDfseXTJRb6PkigP00Iwbe7kFTOqGC/x/swwxzj7MvD29tbMtIQnOJNbloTTwV81N3+XEn0jQLOvPsmuDYwSVYfNhvmhpEuDo4B0nTyTijsD5dCz+viPNiJWMiqqrBq1EaexyXfSqCTxV98nqLF/fHjx+vra3Bttq8Gfr9vnn1KEpafMI/5cHTIO0n4L0S27raghAT604kWXLBscGWAc9CmGRyJODG+Hig5G5tn9uS8lxUxeWZWluX5fPZBZfs88pIrib6FBe2nlkyLmSlIlODGXs3VWNa0MLei4ziiP8uDkRneOCrL0g8LoEL6+mlmdFrtxrcSaLt0IDAT0RVl5Lu/AYzvgRBC0zR1XSOP4I/CV5QTPz2BthLCKCn0KG9wOyYjPFs873tIoD9NCAE5/vz8zMQMszGHksCixaAd3ymH/kzzYgN+aWVzAxs+opnlB/NUx3H0sR97ciXRVxfoZLgGDkFsc8J3mNtJiCkO8PExjIz2sksXvp+BxovioZJhIl4RKj/N84j2CZr5bgJtsxsKdQnOZU4GoZPRj+qYm3+UDOiFeR3t4HyOwWUxcr/runF+V5DNFY9P1zQN3F8bPe97ieC/7pS727CnDxqCa2YItmNKolVGMFw/ExajWWjU2YWCTcCRDP4EA/l4PMLJhsFD9ra9a2V/riT6dp19+BNg557P58mtmoSk8WGG/BeqEyo5ffY0zbhkB8YV/fARDeqra6hOi9V5duBbCTRTmAKaJPU4jpzCZ5fvWmP+/v79OxlmwCcbbz8K5A325FrDYm0d37fdGgn0X6bb1ddBMTCD+MiucbE2FnUjGWQGSUwB3Z5oGHKtwHwl0VcXaCSWX4jOX2JpurKR5AT5ZG0NbHRdl6ym5A+j+LI94N+9LjPDNEgYNqh1rCEvLy8UaxZ9Xww4KdxrOusMm/Zla8o1GXylHec18JLFW3AGZvcWc1KuIoH+NGhKqRuJKDPrvbBghMmXMf8ut6sr29Fdhq/JnIyMXEn07Yrs4Nb3S5Tat5D+BpjKS2s3cYD48yQNLK/l18wzp/X71FL7ZgLtg22WvybTQa/+5AXUG0fDvDqSP96H9Cwv7QuGL4f7IIH+BN7DYC7fkwkQV3vAy6bXG2ReBxL/GP+VGNS5uEh67NpNrb4b3hvOgn4PMh20YP9e0B+qBftFgq966YL9euXVDgx65dV3Ra+8Eh/h3Vde6aWx+zDopbHfj2S2ql4aK66SzBsY/EtjfWwgfT1iXdq25WQNhItdvBEyB4w+xtfcKfSwjJcv+Mia5zfjbYjn52dsyBG6Ol51MSpuvqggqFDOja1Bq5jduRHcMp6grms/2C3WIokRatvWL677JTgejzFGWv1Yol2sDqKY2PhhNdR/8QOd8jGtDtOdL/QKznrNxel0Yt3Lmz6PjV9CJG+O3wqLKGd/hMUayuLvuRrr/U/3Bd1tRrHIjt4IuI8ozdntaC5ChK9+BpBYEVjQrFac8PYl8O5ylNhc0+oeG+818ss2/QNLTFEU2c26R2WpyN7JsDOJZcT1ZcTqVFXl35wU7ia88iZ4zyonW1OW5RdqwoUQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghHouiKPgpNuKREplPUZYld1ZVlel2hHgsUK+Ox2OMEZXtcDjkvqnH5OfPn9goigLJXtd11jtaBz5FVVVlWZ5Op7z385A8RlERnwE1KsYYZtunLMtCrAoSFomMz+fn55y5vir/+9///NeqqnKn96ORK2fFXQDJACoQGwGr2Sf1A3A8HrkdZzLejxAPRSLNMUbvTBQrEmOEack9D+OrraqKzyKBFmJNUKPg1gghmFnbtibWpu97fI7jaGbhIQQ6xvjjx48QAh5qmqZhGDIn9IOSO6tFPjgweDgcuq7LXRQfFqZt13WPNBhb1zUa9aZpzEwavQW5M1lkggPEcG7AFBKrQ3WGfj2GK4BPYXMXwSTQGzCOY96MFtmgV5QujtXLFjcgUsMwTNPE/ajP4zhO0zRNEw/226z8/pw8gNv+MH8V/4n9/l/7kFwra56viS82H0lP5jLzHRvJf/0xHu5Jyg/pug7/xYWY9UkJYXuJPdM0wfznVxzD2/PX4h46A/1D8dd1S1fufBaZ2FSgvRBf5ffv33YprAm+Hk7ThHrlveRd16Ei8Yp93/s6j5/atp1m8BP+aHtZfBJowqbat5TIBZ8py7NRfBOdbZpmKeiU4LZtUQb4LxRL7zHH3+miYRGyWXx9w5DcA39CYebN/6FUf4Lc+SwysbUFbWbDMDRNg/JKbfW1xS4rLQt6YinTrsHXt7c3f5VkhAqH9X3P432doaDv5nOXQNtlHo3jeD6fzZUElg1ujOPIgrFMSW/t2iyUSz1NzmlmuC7/BV1O+nDn85lNu83azZOg7Hmz4OXlBWdjR+3PSXErufNZZGJrCzpxO/idVFjvBuEG7eWkHtplBfNH+q+0lG1RObMEG0igAfJimYNLF0cil77MeFX18u1PQneEL4HYTvwe5gpeYkZ4taWR7m2LZQPvi+J/psbHyZ3PIhM7WNAAxsV7/T7W2L7v+75P3Mc2Vw9WiaV/MDmPXTqv2QsmXdfRDfrXD/ffSKDtUh/9HjA4uHOZO75HxW3otb3j1IaL2TvcqM6+g2UuDtJcYZumCeXK34yXZjjQzBnOTdNIoMUKbC3Q8Md5dzBqIMOBUUW7rivL0geiYQPuDt5Y4hgxV4u8xCeV3G/DBMPfi6Kwj9l9f48E2sMcYfFAXpCiKBLJY2va9z2u6MceeAB+QqkYhiG41alwWNd1vtnm/mVX7+oTJYXNd86859rMYowfTI2PkDWTRT62dnHYXIjhXMbk4LIsy7KEVj4/P/d9X5YlPQ/4hDRj9jCihquqwgZOjorKZS5wIcYXc4EInIoPeDqdzFXmdUdy/jMpyK55vCU3CXQS/wCz988RhzytF9ZpmnhRli5z2UqDANlts3AvvWq4CmJM8Sx8iuDmsttc3kIIdV0XRcGiiGYAfz8cDnbZVKzF2vkmvgibCrR383mxxoV8rWAthUWDIt73Pb4GN8UxXEbdsvgmGzjYW1jeK42fjsfjus/7ByTQ5qTW72RfKkkfc26HaZr8glN+QQLsMaf+/mtYFAwf0RFmS9zmWGN/zHsnoessKV3+6ziOsqDFCuzgg/a+QvoW4OzzcploLqplWZYo92VZ+kplrvKM41jXNQ5jdUWVNuedXBZ3X895UR6zrg9RAr1MUhYAZHQIoSxLSnAywBBc4WRMXuIo8/R9fzgcuD/Mc7JsDibBdggB2hqc3c2r4JgYoy9dOCxcVhYfIBTcPH6/gsLflKids1XcC/sMEvpR8rIsKZohBM4oOR6PDNgIIZRl6ZfBxTJ7fqeZdV0HOwVff/36Vdc1vwZn+PBf8Jlgf4wR1hOkfJom1qLVw+8k0DymaRo/PMt2l4WkaRqeE5HRZVna7GTA/tfXV6ak/xfvp6oq2rnITR90H2ZbeBiGw+FQVRXKJI6hJ8R34LgB7xy2z+dzURRYCxuXRreMig/3Ogv8p2U6S+aK/Gwq0BwANBciGmbXHlzSttBTHIYyjZ11XXtzyTscUXVDCIn/McYILwelln7q5OTYaNvWD8GbLOiP8WkLGs0ht3ESRBPbwj71LmO7jLUAfiwxzNKJYlbXNezZHz9++Nkl7MwhIhurPtnlkHKMse97lBzcJM6QDGn+/v27rmuOoED3aQcE19jYZ8tVrvwVmdnaguasE1/OYF8cDgfWTP9Jd16YzZyu67ANO9pXoRACXwfDs3l/IiOlwqzd1AV4WsxVIX+368ZKS6DNNdIe5vXhcPB9Jo5D+HB4DCabGcutOfcCG2mYwGG2ymGDw6NCvwr/zpvvug43UFUVLsoHhMslxoh2JbjmBNdiRBBKF9oJbMcY2eR/elB6vxwVd8UOURxJeEaYtZjY7N2DgyLphOJUSXVFN5lVlx7nEAI91yEEdi2rqkLlhF2D8+Aw1CUGTuGwq57rv08Ksmseb8knXBw2Oy4QlwY/QJhVFSKOjhFPiLwehoFDyjwbCoaflBhcMQ4hDMNAFxZlN8zNeVVVKHte8f38FNwhpJndNbssn0VRoIcHHeeoCe8BUyI/mERX2TtfxZ2wdRSHuaD9cRzpvOO1YMbCvcj6Nk0Tupa0jnmTyzVR+avNhhgqqu9j0nI5n888kuqPupQsELFuBJ4Emgf42GG+w7Cuawgl9+Dr4XBg20n3RbK2RrKCeXB9KZs1+uq8pDAXDH8wb5U/8RlxYzigKAqGFfkbQAQ3d6JR8bf3uZ7ZXvkp7oytXRwMd2Pt9QMv/hN6inLPTiidGzZLaphDmzlcDssLIajBhWexv8ln5GuZcKQfq8Qd+pq27gQWCbQ/hiMKTHA4EOiRQG7abBp7r5Q/2ziOCHK3eSkljjAznc011Ry9QD+J8fXBDSPb3CdDU+HPA0s8mT5ezG8BDpdSjl+7rsO/OKNdPmhxA/uE2XEDghtm+4izvHg/KM1mltjaTdOgmqGzyZPTmg6zkxpfk9UVzE0CNlffOASUzCnfLhF4A4/B59bisHbOOEYAAAQ1SURBVHccX3bpiEDe0btlboahHycMc6uMnxBzmfhJgvNW+6ko+Eo3Mcf6bC5acMU8PT3R9Qwg4jav6GSLohhmbxtv9W+8HNkyWORlHx+0uRGSMJur5pyGSZ0Jl0HKHr440Vzd41f/LHwiXz18l9OHbW2NBNreLw/hMjaDh/kz+xISnO8Yn4yoS9pgH9qMEWa7FGjiy5W/W/6LPbaPX/e95/p4sXm8AiNuYx8L+mq3DjvpYRzdEr0s0EujY7k4pDemlvHL/C8tHbtcqnSfFUcl0D4p/tDN994wu1xwY3Rr0n5wLW9mLooZCo93dPBIX678ckvYj79/4rrvPdet5M5nkYmtBTrpybZtyzVlGJKRFFxfc6CqyRpJyUJi/BeHZTCS7hV5iR+p3wEJNI9Zloe+75l3dlkAqJVUVZ7Kqy0c0Ph1+WrE90zXP5SrZd7x7x+/7h+e61Zy57PIxKYCnZT45dK9V01aP1GFIBSEFfV8Pvt5AfZHdUhWtmM8LPbss16SBNr+WB6ufk1yil/HcfRLNtPPkBxp15ZkYeONf10tV+iTjZfr2X7iuh95zA+SO59FJvaJ4uDgzNvbGz7xqx//6brOT+ezuS+c1BPO8eUfaQtP87q9OFti0dBap47Adlv9ka8igQZXywM3+JNfo86uvesP/2LzzPW+z+fzr1+/zPlGaKrbws/wXrnyuZZEm9x03fee6xPkzmeRia0FmrLIWbyA00yWTj3azuzeJjY1DBk/9JeQvNpqvHzvhu9pLicNb4QEGrxXHsDLy4v3NiSRyxS+ZDE5Fh7/uga7XGnAQ3/0e+XK+52XJ/zEdZPn+gS581lkYoe1OLyzYpom2K0s3N5GZtHnlGv+lxU7sUG8qyQZK1++vogVafWJgv+JBNr+WB6W43X+YLoR+F9k5fDOO9rZN/LDEuaUNHk1xLJcJaOLyRk+eN0/PNet5M5nkYkdBgnpVUhe18ZlZcyVcv8yZp7EG7msUdR07yexy9E/b/KMi1c7+9GqrZFA85hleQDeB3VV/q5eAhnKbH3vDbP+6nbNN52UK/pY3nuoj1/36nPdSu58FvnATKqiKOq63t+0/D74EDG++eUxsGtvIxMrkjuHRQ78ZBBG6e8TF/ytSMJI7HKJ6i8NlvScLhctEquTO59FPqqqwnoCf347nPg0frkG7sl1M6uDR0M/jG8SESuiivl94eJh5L051uLTQI7xslG8MPdhqlzyqqrwKD0DIfLDF3HGGLHIAN4rEcWqhBCQsB6+MfrrgnUq/Nc4r1MhViRfDovcYLTKVzMViNXxizfF+dUEme9pDbhQJxobPNrT01Pm2xLiMfCSEWbDpxBrE2ZFjpfvH3gA4vwSbjwX23uxIpnzWGSE6lwslmYWa5GkKsT6AZIahYcDg7CjNYYhhBBCCCGEEEIIIYQQQgghhBB/zf8BIKT9hcfpLTQAAAAASUVORK5CYII=" alt="" />
2. Linux下文件操作API
值得注意的是,在现有的linux文件系统相关编程中,存在着两套文件操作API体系(我们时常可以见到open、也可以见到fopen),我们需要明白它们之间的区别
在Linux平台下对文件编程可以使用两类函数
. Linux操作系统文件API(非缓冲文件系统API)
1.1 特点
) 依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出
) 不设置文件结构体指针,只能通过原始的方式读写二进制文件,但效率高、速度快
) 属于低级IO
) 调用open()后返回一个文件描述符(用户程序区的)
) 无缓冲,与read,write等配合使用
) 操作系统设备需要使用open,文件描述符是linux下的一个概念,linux下的一切设备都是以文件的形式操作。如网络套接字、硬件设备等。当然包括操作文件,因此,设备文件不可以当成流式文件来用,只能用open
1.2 包含API
) open
) close
) read
) write
) getc
) getchar
) putc
) putchar . C语言I/O库函数(缓冲文件系统API)
2.1 特点
) 缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问
) 可以对包括字符、字符串、格式化数据、二进制数据进行读写
) 在读写的时候会在内存开辟一个"缓冲区",供程序中的每一个文件使用
) 当执行读文件的操作时,从磁盘文件将数据先读入内存"缓冲区", 装满后再从内存"缓冲区"依此读入接收的变量
) 当执行写文件的操作时,先将数据写入内存"缓冲区",待内存"缓冲区"装满后再写入文件,内存"缓冲区"的大小,影响着实际操作外存的次数,内存"缓冲区"越大,则操作外存的次数就少,执行速度就快、效率高
) 属于高级IO
) 调用fopen()后返回一个文件指针
) 与fread,fwrite等配合使用
) 缓冲文件系统API是在非缓冲文件系统API的基础上扩充而来的,在大多数情况下,我们编程使用"缓冲文件系统API"
) 一般情况下fopen打开普通文件,用open打开设备文件
2.2 包含API
) fopen
) fclose
) fread
) fwrite
) fgetc
) fgets
) fputc
) fputs
) freopen
) fseek
) ftell
) rewind
0x1: 文件的创建
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
1. int open(const char *pathname, int flags);
2. int open(const char *pathname, int flags, mode_t mode);
. pathname
pathname是我们要打开的文件名(包含路径名称,缺省是认为在当前路径下面)
. flags
flags可以去下面的一个值或者是几个值的组合(使用"|"将多个flag组合起来)
) O_RDONLY: 以只读的方式打开文件
) O_WRONLY: 以只写的方式打开文件
) O_RDWR: 以读写的方式打开文件
) O_APPEND: 以追加的方式打开文件
) O_CREAT: 如果文件不存在,则创建一个文件
) O_EXEC: 如果使用了O_CREAT而且文件已经存在,就会发生一个错误
) O_NOBLOCK: 以非阻塞的方式打开一个文件
) O_TRUNC: 如果文件已经存在,则删除文件的内容
) O_ASYNC: 使用一个"signal-driven I/O(信号驱动的IO模式)"打开文件,当文件描述符可用时(文件系统发出信号),open的调用者将获得事件通知
) O_CLOEXEC
)
. mode
要注意的是: mode参数只有在我们在flags中传入了"O_CREAT"才有意义,即只有在新建新文件的时候才需要显示指定mode,用来表示文件的访问权限
) S_IRUSR: 用户可以读
) S_IWUSR: 用户可以写
) S_IXUSR: 用户可以执行
) S_IRWXU: 用户可以读写执行
) S_IRGRP: 组可以读
) S_IWGRP: 组可以写
) S_IXGRP: 组可以执行
) S_IRWXG: 组可以读写执行
) S_IROTH: 其他人可以读
) S_IWOTH: 其他人可以写
) S_IXOTH: 其他人可以执行
) S_IRWXO: 其他人可以读写执行
) S_ISUID: 设置用户执行ID
) S_ISGID: 设置组的执行ID
如果我们打开文件成功,open会返回一个"文件描述符(file discriptor)",我们以后对文件的所有操作就可以对这个文件描述符进行操作了
code
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h> main()
{
int fd, len;
char str[LENGTH];
fd = open("hello.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); /* 创建并打开文件 */
if (fd)
{
printf("open file successful!!\n");
close(fd);
}
close(fd);
return;
}
Relevant Link:
http://www.tutorialspoint.com/unix_system_calls/open.htm
3. int creat(const char *pathname, mode_t mode);
creat() is equivalent to open() with flags equal to O_CREAT|O_WRONLY|O_TRUNC
creat(const char *pathname, mode_t mode) == open(const char *pathname, O_CREAT|O_WRONLY|O_TRUNC, mode_t mode)
4. int openat(int dirfd, const char *pathname, int flags);
5. int openat(int dirfd, const char *pathname, int flags, mode_t mode);
The openat() system call operates in exactly the same way as open
6. FILE *fopen(const char *path, const char *mode);
. filename: 文件路径,默认从当前目录中查找
. mode 打开模式:
) r: 只读方式打开一个文本文件
) rb: 只读方式打开一个二进制文件
) w: 只写方式打开一个文本文件
) wb: 只写方式打开一个二进制文件
) a: 追加方式打开一个文本文件
) ab: 追加方式打开一个二进制文件
) r+: 可读可写方式打开一个文本文件
) rb+: 可读可写方式打开一个二进制文件
) w+: 可读可写方式创建一个文本文件
) wb+: 可读可写方式生成一个二进制文件
) a+: 可读可写追加方式打开一个文本文件
) ab+: 可读可写方式追加一个二进制文件
code
#include <stdio.h> int main ()
{
FILE * pFile;
pFile = fopen ("myfile.txt","w");
if (pFile!=NULL)
{
fputs ("fopen example",pFile);
fclose (pFile);
}
return ;
}
7. FILE *fdopen(int fd, const char *mode);
fdopen,将文件描述词转为文件指针(即实现从非缓存读写到缓存模式读写的转换)
. fd
函数fdopen()会将参数fd的文件描述词,转换为对应的文件指针后返回,随后就可以使用缓存文件模式对文件进行读写
. mode
mode代表着文件指针的流形态,此形态必须和原先文件描述词读写模式相同
要注意的是: mode参数只有在我们在flags中传入了"O_CREAT"才有意义,即只有在新建新文件的时候才需要显示指定mode,用来表示文件的访问权限
) S_IRUSR: 用户可以读
) S_IWUSR: 用户可以写
) S_IXUSR: 用户可以执行
) S_IRWXU: 用户可以读写执行
) S_IRGRP: 组可以读
) S_IWGRP: 组可以写
) S_IXGRP: 组可以执行
) S_IRWXG: 组可以读写执行
) S_IROTH: 其他人可以读
) S_IWOTH: 其他人可以写
) S_IXOTH: 其他人可以执行
) S_IRWXO: 其他人可以读写执行
) S_ISUID: 设置用户执行ID
) S_ISGID: 设置组的执行ID
code
#include <stdio.h> main()
{
//这里0代表基本输出的文件描述符
FILE * fp =fdopen(, "w+");
fprintf(fp, "%s\n", "hello!");
fclose(fp);
}
8. FILE *freopen(const char *path, const char *mode, FILE *stream);
freopen: 打开文件
. path
包含欲打开的文件路径及文件名
. mode
mode代表着文件指针的流形态,此形态必须和原先文件描述词读写模式相同
要注意的是: mode参数只有在我们在flags中传入了"O_CREAT"才有意义,即只有在新建新文件的时候才需要显示指定mode,用来表示文件的访问权限
) S_IRUSR: 用户可以读
) S_IWUSR: 用户可以写
) S_IXUSR: 用户可以执行
) S_IRWXU: 用户可以读写执行
) S_IRGRP: 组可以读
) S_IWGRP: 组可以写
) S_IXGRP: 组可以执行
) S_IRWXG: 组可以读写执行
) S_IROTH: 其他人可以读
) S_IWOTH: 其他人可以写
) S_IXOTH: 其他人可以执行
) S_IRWXO: 其他人可以读写执行
) S_ISUID: 设置用户执行ID
) S_ISGID: 设置组的执行ID . stream
为已打开的文件指针。Freopen()会将原stream所打开的文件流(文件指针)关闭,然后打开参数path的文件
code:
#include <stdio.h> main()
{
FILE * fp;
fp = fopen("/etc/passwd", "r");
fp = freopen("/etc/group", "r", fp);
fclose(fp);
}
9. off_t lseek(int fd, off_t offset, int whence);
lseek()移动文件的读写位置
每一个已打开的文件都有一个读写位置,当打开文件时通常其读写位置是指向文件开头,若是以附加的方式打开文件(如O_APPEND),则读写位置会指向文件尾。当read()或write()时,读写位置会随读写的进行而增加,lseek()便是用来控制该文件的读写位置
. fd
已打开的文件描述符
. offset
需要移动读写位置位移数(这是一个绝对数,而具体怎么解释这个数值,需要根据whence而定)
. whence
whence为下列其中一种:
) SEEK_SET: 参数offset即为新的读写位置
1.1) 欲将读写位置移到文件开头
lseek(int fildes,,SEEK_SET);
) SEEK_CUR: 以目前的读写位置往后增加offset个位移量(允许负值)
2.1) 想要取得目前文件位置
lseek(int fildes, , SEEK_CUR);
) SEEK_END: 将读写位置指向文件尾后再增加offset个位移量(允许负值)
3.1) 欲将读写位置移到文件尾
lseek(int fildes, , SEEK_END);
code
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h> char buf1[] = "abcdefghij";
char buf2[] = "ABCDEFGHIJ"; int main(void)
{
int fd, size;
if ((fd = creat("file.hole", S_IRUSR|S_IWUSR)) < )
{
printf("creat error\n");
return -;
}
size = sizeof buf1 - ;
if (write(fd, buf1, size) != size)
{
printf("buf1 write error\n");
return -;
}
/* offset now = 10 */
if (lseek(fd, , SEEK_SET) == -)
{
printf("lseek error\n");
return -;
}
/* offset now = 16384 */
size = sizeof buf2 - ;
if (write(fd, buf2, size) != size)
{
printf("buf2 write error\n");
return -;
}
/* offset now = 16394 */
return ;
}
10. int fseek(FILE *stream, long offset, int whence);
fseek()移动"文件流"(注意是文件流)的读写位置
. *stream
已打开的文件指针
. offset
和lseek中的offset意义一样,offset为根据参数whence来移动读写位置的位移数
. whence
) SEEK_SET: 从距文件开头offset位移量为新的读写位置
1.1) 欲将读写位置移动到文件开头时
fseek(FILE*stream, , SEEK_SET);
) SEEK_CUR: 以目前的读写位置往后增加offset个位移量(允许负值)
) SEEK_END: 将读写位置指向文件尾后再增加offset个位移量(允许负值)
3.1) 欲将读写位置移动到文件尾时
fseek(FILE*stream, , SEEK_END);
code:
#include <stdio.h> main()
{
FILE * stream;
long offset;
fpos_t pos;
stream = fopen("/etc/passwd", "r");
fseek(stream, , SEEK_SET);
//fseek()不像lseek()会返回读写位置,因此必须使用ftell()来取得目前读写的位置
printf("offset=%d\n", ftell(stream));
rewind(stream);
fgetpos(stream, &pos);
printf("offset=%d\n", pos);
pos = ;
fsetpos(stream, &pos);
printf("offset = %d\n", ftell(stream));
fclose(stream);
}
0x2: 文件的读取
1. ssize_t read(int fd, void *buf, size_t );
read()从已打开的"文件描述符"中读取数据,对于read的使用,我们需要记住以下几点
. read()会把参数fd所指的文件传送count个字节到buf指针所指的内存中
. 若参数count为0,则read()不会有作用并返回0
. 返回值为实际读取到的字节数,如果返回0,表示已到达文件尾或是无可读取的数据,如果顺利read()会返回实际读到的字节数,最好能将返回值与参数count作比较,若返回的字节数比要求读取的字节数少,则有可能读到了文件尾、
从管道(pipe)或终端机读取,或者是read()被信号中断了读取动作
. 文件读写位置会随读取到的字节移动(即读多少,前进多少)
. 当读取过程中有错误发生时则返回-,错误代码存入errno中,而文件读写位置则无法预期
参数说明
. fd
已经打开的文件描述符
. *buf
保存读取数据的一段内存空间
. count
需要读取的字节数
code:
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h> main()
{
int fd, size;
char s[] = "Linux Programmer!\n", d[] = "Modified the file!\n", buffer[];
struct stat stat_modified, stat_notmodified; fd = open("/tmp/just4fun", O_RDWR | O_CREAT);
write(fd, s, sizeof(s));
close(fd); printf("read the file! \n");
fd = open("/tmp/just4fun", O_RDONLY);
size = read(fd, buffer, sizeof(buffer));
close(fd); return;
}
2. size_t fread(void * ptr,size_t size, size_t nmemb, FILE * stream);
fread()从"文件流"读取数据
fread()用来从"文件流"(注意和read()从文件描述符中读取数据作区分)中读取数据
Fread()会返回实际读取到的nmemb数目,如果此值比参数nmemb 来得小,则代表可能读到了文件尾或有错误发生,这时必须用feof()或ferror()来决定发生什么情况
. ptr
指向欲存放读取进来的数据空间
. size
每个字段为size字节
. nmemb
读取加n个字段(读取的字符数以参数size * nmemb来决定)
. stream
已打开的文件指针
code:
#include <stdio.h>
#define nmemb 3 struct test
{
char name[];
int size;
}s[nmemb]; main()
{
FILE * stream;
int i;
stream = fopen("/tmp/fwrite","r");
fread(s, sizeof(struct test), nmemb, stream);
fclose(stream);
for(i=;i<nmemb;i++)
{
printf("name[%d]=%-20s:size[%d]=%d\n", i, s[i].name, i, s[i].size);
}
}
0x3: 文件的写入
1. ssize_t write(int fd, const void *buf, size_t count);
write()将数据写入已打开的文件内
write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。同时,文件读写位置也会随之移动。如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h> main()
{
int fd,size;
char s[] = "Linux Programmer!\n", buffer[];
fd = open("/tmp/temp", O_WRONLY|O_CREAT);
write(fd,s,sizeof(s));
close(fd);
return;
}
0x4: 文件属性的操作
1. mode_t umask(mode_t mask);
umask()的作用在于设置建立新文件时的权限遮罩,关于文件权限的相关知识,请参阅另一篇文章
http://www.cnblogs.com/LittleHann/p/3862652.html
umask()会将系统umask值设成参数mask&0777后的值,然后将先前的umask值返回。简单来说,就是改变当前文件系统的"默认权限",这将直接影响在新建文件时,文件的默认文件权限
. mask
) S_IRWXU: : user (file owner) has read, write and execute permission
) S_IRUSR: user has read permission
) S_IWUSR: user has write permission
) S_IXUSR: user has execute permission
) S_IRWXG: group has read, write and execute permission
) S_IRGRP: group has read permission
) S_IWGRP: group has write permission
) S_IXGRP: group has execute permission
) S_IRWXO: others have read, write and execute permission
) S_IROTH: others have read permission
) S_IWOTH: others have write permission
) S_IXOTH: others have execute permission
code
#include <unistd.h>
#include <sys/stat.h>
#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) int main(void)
{
mode_t mask = umask();
if(creat("foo",RWRWRW)<)
{
printf("create error for foo\n");
}
umask(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
if(creat("bar",RWRWRW)<)
{
printf("creat error for bar\n");
}
exit();
}
2. int access(const char * pathname,int mode);
access()会检查是否可以读/写某一已存在的文件
. pathname
带检查的文件路径
. mode
参数mode可以取以下任意值或其组合
) R_OK: 测试读许可权
) W_OK: 测试写许可权
) X_OK: 测试执行许可权
) F_OK: 测试文件是否存在
. 返回值
若所有欲查核的权限都通过了检查则返回0值,表示成功,只要有一权限被禁止则返回-
. 错误代码
) EACCESS: 参数pathname所指定的文件不符合所要求测试的权限
) EROFS: 欲测试写入权限的文件存在于只读文件系统内
) EFAULT: 参数pathname指针超出可存取内存空间
) EINVAL: 参数mode不正确
) ENAMETOOLONG参数pathname太长
) ENOTDIR: 参数pathname为一目录
) ENOMEM: 核心内存不足
) ELOOP: 参数pathname有过多符号连接问题
) EIO I/O: 存取错误。
/*
值得注意的是:
由于access()只作权限的核查,并不理会文件形态或文件内容,因此,如果一目录表示为"可写入",表示可以在该目录中建立新文件等操作,而非意味此目录可以被当做文件处理
*/
code
#include <stdio.h>
#include <unistd.h> int main(void)
{
if(access("test.txt", R_OK)==)
{
printf("READ OK\n");
}
if(access("test.txt", W_OK)==)
{
printf("WRITE OK\n");
}
if(access("test.txt", X_OK)==)
{
printf("EXEC OK\n");
}
if(access("test.txt", F_OK)==)
{
printf("File exist\n");
}
}
3. int stat(const char * file_name, struct stat *buf);
函数说明stat()用来将参数file_name所指的"文件状态属性",复制到参数buf所指的结构中
struct stat的数据结构如下
struct stat
{
dev_t st_dev; /*文件的设备编号*/
ino_t st_ino; /*文件的i-node*/ /*
文件的类型和存取的权限
st_mode 则定义了下列数种情况
1) S_IFMT: 0170000: 文件类型的位遮罩
2) S_IFSOCK: 0140000: scoket
3) S_IFLNK: 0120000: 符号连接
4) S_IFREG: 0100000: 一般文件
5) S_IFBLK: 0060000: 区块装置
6) S_IFDIR: 0040000: 目录
7) S_IFCHR: 0020000: 字符装置
8) S_IFIFO: 0010000: 先进先出
9) S_ISUID: 04000: 文件的(set user-id on execution)位
10) S_ISGID: 02000: 文件的(set group-id on execution)位
11) S_ISVTX: 01000: 文件的sticky位
若一目录具有sticky位(S_ISVTX),则表示在此目录下的文件只能被该文件所有者、此目录所有者或root来删除或改名
12) S_IRUSR(S_IREAD): 00400: 文件所有者具可读取权限
13) S_IWUSR(S_IWRITE): 00200: 文件所有者具可写入权限
14) S_IXUSR(S_IEXEC): 00100: 文件所有者具可执行权限
15) S_IRGRP: 00040: 用户组具可读取权限
16) S_IWGRP: 00020: 用户组具可写入权限
17) S_IXGRP: 00010: 用户组具可执行权限
18) S_IROTH: 00004: 其他用户具可读取权限
19) S_IWOTH: 00002: 其他用户具可写入权限
20) S_IXOTH: 00001: 其他用户具可执行权限
上述的文件类型在POSIX中定义了检查这些类型的宏定义
1) S_ISLNK(st_mode): 判断是否为符号连接
2) S_ISREG(st_mode): 是否为一般文件
3) S_ISDIR(st_mode): 是否为目录
4) S_ISCHR(st_mode): 是否为字符装置文件
5) S_ISBLK(s3e): 是否为先进先出
6) S_ISSOCK(st_mode): 是否为socket
*/
mode_t st_mode;
nlink_t st_nlink; /*连到该文件的硬连接数目,刚建立的文件值为1*/
uid_t st_uid; /*文件所有者的用户识别码*/
gid_t st_gid; /*文件所有者的组识别码*/
dev_t st_rdev; /*若此文件为装置设备文件,则为其设备编号*/
off_t st_size; /*文件大小,以字节计算*/
unsigned long st_blksize; /*文件系统的I/O 缓冲区大小*/
unsigned long st_blocks; /*占用文件区块的个数,每一区块大小为512 个字节*/ /*
文件最近一次被存取或被执行的时间,一般只有在用
1. mknod
2. utime
3. read
4. write
5. tructate
时才会改变这个字段的值
*/
time_t st_atime; /*
文件最后一次被修改的时间,一般只有在用
1. mknod
2. utime
3. write时
才会改变这个字段的值
*/
time_t st_mtime; /*
time of last change
i-node最近一次被更改的时间
*/
time_t st_ctime;
};
返回值: 执行成功则返回0,失败返回-1,错误代码存于errno
错误代码
. ENOENT: 参数file_name指定的文件不存在
. ENOTDIR: 路径中的目录存在但却非真正的目录
. ELOOP: 欲打开的文件有过多符号连接问题,上限为16符号连接
. EFAULT: 参数buf为无效指针,指向无法存在的内存空间
. EACCESS: 存取文件时被拒绝
. ENOMEM: 核心内存不足
. ENAMETOOLONG: 参数file_name的路径名称太长
code
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h> #include <fcntl.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <string.h> void fileperm(struct stat *buf, char *perm)
{
strcpy(perm, "----------");
perm[] = '?';
mode_t mode;
mode = buf->st_mode;
switch (mode & S_IFMT)
{
case S_IFSOCK:
perm[] = 's';
break;
case S_IFLNK:
perm[] = 'l';
break;
case S_IFREG:
perm[] = '-';
break;
case S_IFBLK:
perm[] = 'b';
break;
case S_IFDIR:
perm[] = 'd';
break;
case S_IFCHR:
perm[] = 'c';
break;
case S_IFIFO:
perm[] = 'p';
break;
} if (mode & S_IRUSR)
perm[] = 'r';
if (mode & S_IWUSR)
perm[] = 'w';
if (mode & S_IXUSR)
perm[] = 'x';
if (mode & S_IRGRP)
perm[] = 'r';
if (mode & S_IWGRP)
perm[] = 'w';
if (mode & S_IXGRP)
perm[] = 'x';
if (mode & S_IROTH)
perm[] = 'r';
if (mode & S_IWOTH)
perm[] = 'w';
if (mode & S_IXOTH)
perm[] = 'x';
perm[] = '\0';
} int main(int argc, char *argv[])
{
struct stat sb;
struct passwd *passwd;
struct group *group;
char perm[] = {}; if (argc != )
{
fprintf(stderr, "Usage: %s <pathname>\n", argv[]);
exit(EXIT_FAILURE);
} if (stat(argv[], &sb) == -)
{
perror("stat");
exit(EXIT_SUCCESS);
}
passwd = getpwuid (sb.st_uid);
group = getgrgid (sb.st_gid); printf("File type: "); switch (sb.st_mode & S_IFMT)
{
case S_IFBLK: printf("block device\n"); break;
case S_IFCHR: printf("character device\n"); break;
case S_IFDIR: printf("directory\n"); break;
case S_IFIFO: printf("FIFO/pipe\n"); break;
case S_IFLNK: printf("symlink\n"); break;
case S_IFREG: printf("regular file\n"); break;
case S_IFSOCK: printf("socket\n"); break;
default: printf("unknown?\n"); break;
} printf("I-node number: %ld\n", (long) sb.st_ino); printf("Mode: %lo (octal)\n", (unsigned long) sb.st_mode); printf("Link count: %ld\n", (long) sb.st_nlink);
printf("Ownership: UID=%ld GID=%ld\n", (long) sb.st_uid, (long) sb.st_gid);
printf("Ownership: UID=%s GID=%s\n", passwd->pw_name, group->gr_name); printf("File Permission Bits: %o %s\n", sb.st_mode & , perm); printf("Preferred I/O block size: %ld bytes\n", (long) sb.st_blksize);
printf("File size: %lld bytes\n", (long long) sb.st_size);
printf("Blocks allocated: %lld\n", (long long) sb.st_blocks); printf("Last status change: %s", ctime(&sb.st_ctime));
printf("Last file access: %s", ctime(&sb.st_atime));
printf("Last file modification: %s", ctime(&sb.st_mtime)); exit(EXIT_SUCCESS);
}
4. int fstat(int fd, struct stat *buf);
Fstat()与stat()作用完全相同,不同处在于传入的参数为已打开的"文件描述符"
返回值 执行成功则返回0,失败返回-,错误代码存于errno
code
#include <sys/stat.h>
#include <unistd.h>
#include <fcntk.h> main()
{
struct stat buf;
int fd;
fd = open("/etc/passwd", O_RDONLY);
fstat(fd, &buf);
printf("/etc/passwd file size +%d\n", buf.st_size);
}
5. lstat(const char *pathname, struct stat *buf);
lstat()与stat()作用完全相同,都是取得参数file_name所指的文件状态,其差别在于,当文件为"符号连接"时,lstat()会返回该link本身的状态(而不会去继续跟踪符号连接的终点)
返回值 执行成功则返回0,失败返回-,错误代码存于errno
0x5: 文件的错误处理
1. void clearerr(FILE * stream);
clearerr()清除参数stream指定的文件流所使用的错误旗标
code
#include <stdio.h> int main ()
{
FILE * pFile;
//这里以只读方式打开
pFile = fopen("myfile.txt","r");
if (pFile==NULL)
{
perror ("Error opening file");
}
else
{
//往只读的文件描述符中写入数据,引发错误
fputc ('x',pFile);
if (ferror (pFile))
{
printf ("Error Writing to myfile.txt\n");
//清除错误
clearerr (pFile);
}
fgetc (pFile);
if (!ferror (pFile))
{
printf ("No errors reading myfile.txt\n");
} fclose (pFile);
}
return ;
}
0x6: 文件的删除
1. int unlink(const char *pathname);
unlink()会删除参数pathname指定的文件
. 如果该文件名为最后连接点,但有其他进程打开了此文件,则在所有关于此文件的文件描述词皆关闭后才会删除
. 如果参数pathname为一符号连接,则此符号连接会被删除 返回值
. 成功则返回0
. 失败返回- 错误原因存于errno
错误代码EROFS文件存在于只读文件系统内
. EFAULT: 参数pathname指针超出可存取内存空间
. ENAMETOOLONG: 参数pathname太长
. ENOMEM: 核心内存不足
. ELOOP: 参数pathname有过多符号连接问题
. EIO: I/O存取错误
2. int unlinkat(int dirfd, const char *pathname, int flags);
0x7: 文件的关闭
1. int close(int fd);
close()关闭文件
当使用完文件后若已不再需要则可使用close()关闭该文件,close()会让数据写回磁盘,并释放该文件所占用的资源
. fd
为先前由open()或creat()所返回的文件描述符
若文件顺利关闭则返回0,发生错误时返回-
code:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#define LENGTH 100 main()
{
int fd, len;
char str[LENGTH];
fd = open("hello.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); /* 创建并打开文件 */
if (fd)
{
write(fd, "Hello, Software Weekly", strlen("Hello, software weekly")); /* 写入 Hello, software weekly字符串 */
close(fd);
} fd = open("hello.txt", O_RDWR);
len = read(fd, str, LENGTH); /* 读取文件内容 */
str[len] = '\0';
printf("%s\n", str);
close(fd);
}
2. int fclose (FILE *stream);
fclose()用来关闭先前fopen()打开的文件。此动作会让缓冲区内的数据写入文件中,并释放系统所提供的文件资源。若关文件动作成功则返回0,有错误发生时则返回EOF并把错误代码
Relevant Link:
http://www.iteedu.com//os/linux/linuxprgm/linuxcfunctions/index.php
http://dev.yesky.com/468/7601968.shtml
http://fanqiang.chinaunix.net/a4/b2/20010508/113315.html
http://redwolf.blog.51cto.com/427621/154255
3. Linux下文件目录操作API
0x1: 新建目录
1. int mkdir(const char *path, mode_t mode);
. path
要新建的目录路径
. mode
新建目录的访问权限属性(linux下文件、目录的属性操作都是一样的)
http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysstat.h.html
code
#include <sys/stat.h>
#include <sys/types.h> main()
{
/*
mkdir会根据传入的路径参数造一个新目录出来
1. 如果该目录或档案已经存在,则操作失败
2. mode 设置为0700,开始的0表示八进制
*/
if(mkdir("/home/zxc/z", ) == -)
{
perror("Couldn't create the directory.\n");
return
}
}
0x2: 打开目录
1. int open( const char * pathname, int flags);
open除了可以用来打开文件之外,同样可以打开目录,只要在调用的时候传入O_DIRECTORY的flag即可
2. DIR * opendir(const char * name);
//DIR结构体类似于FILE,是一个内部结构,用于保存当前正在被读取的目录的有关信息
struct __dirstream
{
void *__fd;
char *__data;
int __entry_data;
char *__ptr;
int __entry_ptr;
size_t __allocation;
size_t __size;
__libc_lock_define (, __lock)
};
typedef struct __dirstream DIR;
opendir()用来打开参数name指定的目录,并返回DIR*形态的目录流,和open()类似,接下来对目录的读取和搜索都要使用此返回值
返回值
. 成功则返回DIR*型态的目录流
. 打开失败则返回NULL 错误代码
. EACCESS: 权限不足
. EMFILE: 已达到进程可同时打开的文件数上限
. ENFILE: 已达到系统可同时打开的文件数上限
. ENOTDIR: 参数name非真正的目录
. ENOENT: 参数name指定的目录不存在,或是参数name为一空字符串
. ENOMEM: 核心内存不足
3. struct dirent readdir(DIR *);
//dirent不仅仅指向目录,还指向目录中的具体文件
struct dirent
{
long d_ino; /* inode number 索引节点号 */
off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
unsigned short d_reclen; /* length of this d_name 文件名长 */
unsigned char d_type; /* the type of d_name 文件类型 */
char d_name [NAME_MAX+]; /* file name (null-terminated) 当前目录下的所有文件名(包括目录本身),最长255字符 */
}
打开指定目录的子路径,可以反复调用本函数来得到制定目录的所有子路径信息。当执行到最后一个目录或者文件的时候,将返回NULL
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h> int main(void)
{
struct stat fStat;
DIR *dir;
struct dirent *fileInfo = NULL; if (- == lstat("test.txt", &fStat))
{
perror("");
return -;
} if (S_ISDIR(fStat.st_mode))
{
printf("INFO: The path is a directory!\n");
}
else
{
printf("INFO: The path is a file!\n");
return ;
} //If it is a dir, print the files' names in this directory.
dir = opendir("testdir");
if (NULL == dir)
{
perror("");
return -;
} fileInfo = readdir(dir);
while (NULL != fileInfo)
{
printf("INFO: File name is %s!\n", fileInfo->d_name);
fileInfo = readdir(dir);
} return ;
}
4. void rewinddir(DIR *dr);
重置读取目录的位置为开头,在readdir循环遍历当前目录所有文件时配合使用
5. int chdir(const char *path);
chdir接受目录路径名,成功时当前工作目录改变,并均返回0。失败,返回-1.并设置errno
6. int fchdir(int fd);
fchdir接收指向已打开目录的文件描述符,成功时当前工作目录改变,并均返回0。失败,返回-1.并设置errno
0x3: 读取目录属性
1. S_ISDIR(stat.st_mode)
判断是否是目录,传入参数是(struct stat)
2. int stat(const char * file_name, struct stat *buf);
stat除了可以用来获取文件的属性之外,同样也可以获取目录的属性,事实上,linux下目录和文件并没有太大的区别,所有的文件、设备都被抽象为了"文件"来看待
0x4: 删除目录
1. int remove(const char *pathname) ;
remove()会删除参数pathname指定的文件
. 如果参数pathname为一文件,则调用unlink()处理
. 若参数pathname为一目录,则调用rmdir()来处理(remove只是一个中转函数) 返回值
. 成功则返回0
. 失败则返回- 错误原因存于errno
. EROFS: 欲写入的文件存在于只读文件系统内
. EFAULT: 参数pathname指针超出可存取内存空间
. ENAMETOOLONG: 参数pathname太长
. ENOMEM: 核心内存不足
. ELOOP: 参数pathname有过多符号连接问题
. EIO: I/O存取错误
2. int rmdir(const char *path);
标准的POSIX调用rmdir()将目录从文件系统层次上移除
1. 调用成功,rmdir从文件系统移除path,并返回0.path指向的目录必须唯一
2. 调用失败时,rmdir()返回-1,并设置errno
0x5: 获取当前目录
1. char *getcwd(char *buffer,size_t size);
. 执行成功
成功调用getcwd()会以"绝对路径名"形式复制当前"工作目录"至由buf指向的长度size字节的缓冲区。并返回一个指向buf的指针
. 执行失败
失败时,调用返回NULL,并设置errno
) EFAULT
) EINVAL
) ENOENT
) ERANGE
code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h> void main()
{
char cwd[];
getcwd(cwd, sizeof(cwd));
if(!cwd)
{
perror("getcwd");
exit(EXIT_FAILURE);
}
printf("cwd = %s\n",cwd);
}
2. char * getwd(char *buf);
调用getwd会复制当前"工作目录"至长度至少PATH_MAX字节的buf。成功调用返回buf指针,失败返回NULL
getwd()这个函数是为了向后兼容,因此不建议使用,推荐getcwd()
3. char * get_current_dir_name(void);
这个函数和 getcwd()的作用一样,都是获得当前"工作目录"的"绝对路径"
#include <stdio.h>
#include <stdlib.h>
#define _GNU_SOURCE
#include <unistd.h> int main ()
{
char *path; path = get_current_dir_name(); printf ("当前路径为:%s\n", path); free (path); return ();
}
4. int readlink(const char * path, char * buf, size_t bufsiz);
readlink()会将参数path的符号连接内容(真正指向的目标文件的路径)存到参数buf 所指的内存空间, 返回的内容不是以NULL作字符串结尾, 但会将字符串的字符数返回. 若参数bufsiz小于符号连接的内容长度, 过长的内容会被截断.
返回值
. 执行成功则传符号连接所指的文件路径字符串
. 失败则返回-, 错误代码存于errno. 错误代码:
. EACCESS: 取文件时被拒绝,权限不够
. EINVAL: 参数bufsiz为负数
. EIO: I/O存取错误
. ELOOP: 欲打开的文件有过多符号连接问题
. ENAMETOOLONG: 参数path的路径名称太长
. ENOENT: 参数path所指定的文件不存在
. ENOMEM: 核心内存不足
. ENOTDIR: 参数path路径中的目录存在但却非真正的目录
code
#include <stdio.h>
#include <unistd.h> int main()
{
char path[], buf[];
sprintf(path, "/proc/%d/exe", getpid());
readlink(path, buf, sizeof(buf));
printf("%s/n", buf);
return ;
}
Relevant Link:
http://wenku.baidu.com/view/788915a8d1f34693daef3e6c.html
http://www.averainy.info/linux-system-programming-directory-operation-function-summary/
http://www.360doc.com/relevant/162835139_more.shtml
http://www.jb51.net/article/40594.htm
http://icarusliu.iteye.com/blog/1528703
4. Linux下的其他设备操作API
0x1: int ioctl(int fd, unsigned long request, ../* void *arg */.); (硬件信息相关)
. fd
ioctl函数的第一个参数fd,可以表示一个打开的文件(文件句柄)或网络套接字 . request
第二个和第三个参数体现了函数的家族特色,参数二request根据函数功能分类定义了多组宏,这里以和网卡相关信息的宏为例子
) SIOCGIFCONF struct ifconf 获得所有接口列表
) SIOCGIFADDR struct ifreq 获得接口地址
) SIOCGIFFLAGS struct ifreq 获得接口标志
) SIOCGIFBRDADDR struct ifreq 获得广播地址
) SIOCGIFNETMASK struct ifreq 获得子网掩码
更多关于这个参数列表请参阅
http://manpages.courier-mta.org/htmlman2/ioctl_list.2.html . arg
参数三总是一个指针,指针的类型依赖于参数二request
code
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h> #define MAXINTERFACES 16 /* 最大接口数 */ int fd; /* 套接字 */
int if_len; /* 接口数量 */
struct ifreq buf[MAXINTERFACES]; /* ifreq结构数组 */
struct ifconf ifc; /* ifconf结构 */ int main(argc, argv)
{
/* 建立IPv4的UDP套接字fd */
if ((fd = socket(AF_INET, SOCK_DGRAM, )) == -)
{
perror("socket(AF_INET, SOCK_DGRAM, 0)");
return -;
} /* 初始化ifconf结构 */
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = (caddr_t) buf; /* 获得接口列表 */
if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) == -)
{
perror("SIOCGIFCONF ioctl");
return -;
} if_len = ifc.ifc_len / sizeof(struct ifreq); /* 接口数量 */
printf("接口数量:%d/n/n", if_len); while (if_len– > ) /* 遍历每个接口 */
{
printf("接口:%s/n", buf[if_len].ifr_name); /* 接口名称 */ /* 获得接口标志 */
if (!(ioctl(fd, SIOCGIFFLAGS, (char *) &buf[if_len])))
{
/* 接口状态 */
if (buf[if_len].ifr_flags & IFF_UP)
{
printf("接口状态: UP/n");
}
else
{
printf("接口状态: DOWN/n");
}
}
else
{
char str[];
sprintf(str, "SIOCGIFFLAGS ioctl %s", buf[if_len].ifr_name);
perror(str);
} /* IP地址 */
if (!(ioctl(fd, SIOCGIFADDR, (char *) &buf[if_len])))
{
printf("IP地址:%s/n",
(char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr));
}
else
{
char str[];
sprintf(str, "SIOCGIFADDR ioctl %s", buf[if_len].ifr_name);
perror(str);
} /* 子网掩码 */
if (!(ioctl(fd, SIOCGIFNETMASK, (char *) &buf[if_len])))
{
printf("子网掩码:%s/n",
(char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr));
}
else
{
char str[];
sprintf(str, "SIOCGIFADDR ioctl %s", buf[if_len].ifr_name);
perror(str);
} /* 广播地址 */
if (!(ioctl(fd, SIOCGIFBRDADDR, (char *) &buf[if_len])))
{
printf("广播地址:%s/n",
(char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr));
}
else
{
char str[];
sprintf(str, "SIOCGIFADDR ioctl %s", buf[if_len].ifr_name);
perror(str);
} /*MAC地址 */
if (!(ioctl(fd, SIOCGIFHWADDR, (char *) &buf[if_len])))
{
printf("MAC地址:%02x:%02x:%02x:%02x:%02x:%02x/n/n",
(unsigned char) buf[if_len].ifr_hwaddr.sa_data[],
(unsigned char) buf[if_len].ifr_hwaddr.sa_data[],
(unsigned char) buf[if_len].ifr_hwaddr.sa_data[],
(unsigned char) buf[if_len].ifr_hwaddr.sa_data[],
(unsigned char) buf[if_len].ifr_hwaddr.sa_data[],
(unsigned char) buf[if_len].ifr_hwaddr.sa_data[]);
}
else
{
char str[];
sprintf(str, "SIOCGIFHWADDR ioctl %s", buf[if_len].ifr_name);
perror(str);
}
}//–while end //关闭socket
close(fd);
return ;
}
Relevant Link:
http://manpages.courier-mta.org/htmlman2/ioctl_list.2.html
http://www.360doc.com/content/12/0314/15/5782959_194281431.shtml
Copyright (c) 2014 LittleHann All rights reserved
Linux File、File Directory IO Operation Summary(undone)的更多相关文章
- System.IO中的File、FileInfo、Directory与DirectoryInfo类(实例讲解)
一.建立的文件夹(对这些文件进行以上四个类的操作): 父目录: 父目录的子目录以及父目录下的文件: 子目录下的文件: 二.效果图 三.代码实现 using System; using System.I ...
- 小项目:mini资源管理器【使用IO流:包含(Directory与DirectoryInfo、File与FileInfo的用法)】
主界面是这样的 1.在点击查询引发的事件时把TextBox.Text输入的目录地址加载到TreeList控件里. private void btnSelect_Click(object sender, ...
- 使用File、Path和Directory进行常见的操作
我们偶尔会用到文件操作,其中File.Path和Directory这三个类是比较常见的,今天写了一个测试demo,也是顺便学习一下,记录一二. BTW,使用这几个类的时候需要引用using Syste ...
- 图解 Java IO : 一、File源码
Writer :BYSocket(泥沙砖瓦浆木匠) 微 博:BYSocket 豆 瓣:BYSocket FaceBook:BYSocket Twitter ...
- 13、IO (File、递归)
File File类的概述和作用 * A:File类的概述和作用 * a: File的概念 * File类是文件和目录路径名的抽象表示形式 * Java中把文件或者目录(文件夹)都封装成File对象 ...
- CMake error:System Error:No such file or directory CMake error:Could not open file for write in copy operation xxxx.ros_Config.cmake.tmp.
微型电脑或嵌入式与电脑还是有点不同的,在微型电脑上ros indigo 版本下利用catkin编译如果你遇到如下错误: CMake error:System Error:No such file or ...
- Linux命令——cp、rm、mv、touch、file、dir
cp copy 拷贝文件 拷贝过程不指定目标文件名 则目标文件名和源文件名一样 [root@WebServer ~]# cp /91xueit/teacher.txt 51cto/ 拷贝过程指定目标文 ...
- Python ValueError: IO operation on closed file
ValueError IO operation on closed file表示处理了已经被关闭的数据,在python 中 with语句的上下文会帮助处理,也就是说,当python的处理代码不对齐的时 ...
- C#文件与流(FileStream、StreamWriter 、StreamReader 、File、FileInfo、Directory、directoryInfo、Path、Encoding)
(FileStream.StreamWriter .StreamReader .File.FileInfo.Directory.DirectoryInfo.Path.Encoding) C#文 ...
随机推荐
- poj 1046 Color Me Less
Color Me Less Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 33007 Accepted: 16050 D ...
- 【WPF】WPF中调用Winform
1.添加两个引用:WindowsFormsIntegration.dll(负责整合WPF和Windows).System.Windows.Forms.2.在 XAML文件中添加两个引用(粗体部分): ...
- 支持MVC的代码生成运行效果 C# ASP.NET
做技术的,你若还不懂MVC的话,你好像是外星球来的一样,或者还生活在远古社会里一样,这几天正好没什么事情干,可以静心学习学习MVC技术,顺便把原先的代码生成器修改了一下,只要数据库里设计好了数据结构, ...
- [py] 导入模块 reload(sys)
#!/usr/bin/env python # coding: utf-8 import sys reload(sys) #<------这个是什么意思 sys.setdefault ...
- C# 与 Unity 同名函数
1,Random,直接使用Random会报错,要么使用UnityEngine.Random,要么使用System.Random
- XXOOJL
她的鞋子放在外面没拿进来很显眼,我们俩正抱在床上,刚做完什么也没穿,她也没擦.听到门外的脚步声.赶紧穿.她在我房间里没出声,但我父亲肯定看出来了.于是问我:母亲去哪了,然后他去找她. 太尴尬了,那晚我 ...
- Photoshop Cc高级设计师培训视频教程(共109节课程)
Photoshop Cc高级设计师培训视频教程(共109节课程) 专业培训Photoshop技能,其他网站收费内容,这里收集了,免费分享给你们哦~ 以下为部分截图: 下载地址: http://fu83 ...
- java.util.ConcurrentModificationException 解决办法
在使用iterator.hasNext()操作迭代器的时候,如果此时迭代的对象发生改变,比如插入了新数据,或者有数据被删除. 则使用会报以下异常:Java.util.ConcurrentModific ...
- 集DDD,TDD,SOLID,MVVM,DI,EF,Angularjs等于一身的.NET(C#)开源可扩展电商系统–Virto Commerce
今天一大早来看到园友分享的福利<分享一个前后端分离方案源码-前端angularjs+requirejs+dhtmlx 后端asp.net webapi>,我也来分享一个吧.以下内容由笔者写 ...
- Django1.8教程——安装Django
本书介绍 你是不是对Django的学习感到迷茫?是不是对网上零星的教程感到绝望?是不是苦于没有可以迅速上手的实例而发愁?如果你同我一样有这些感受,那么<Django.By.Example> ...