Java坦克大战06

8.IO流应用01

坦克大战6.0版

增加功能:

  1. 防止敌人坦克重叠运动
  2. 记录玩家的成绩(累计击毁坦克数),存盘退出
  3. 记录当时的敌人坦克坐标,存盘退出
  4. 玩游戏时,可以选择是开新游戏还是继续上局游戏

8.1防止敌人坦克重叠运动

8.1.1思路分析

按照目标坦克的向右下左四种情况分析,每一种情况又分为两种小情况,一种八种情况。

8.1.2代码实现

8.1.2.1修改处1

在EnemyTank类中:

  1. 增加了增加一个成员属性,EnemyTank 可以得到敌人坦克成员的 Vector,用于循环比较是否重叠
  2. 新增一个方法setEnemyTanks,可以将MyPanel的成员 Vector enemyTanks = new Vector<>() 设置到Enemy 的成员enemyTank
  3. 编写方法isTouchEnemyTank(),判断当前敌人坦克是否和enemyTanks中的其他坦克发生了重叠或碰撞
  4. 在run方法中,在根据坦克的方法来继续移动的判断条件中,调用isTouchEnemyTank方法,如果返回值不为true,则可以继续运行
  1. package li.TankGame.version06;
  2. import java.util.Vector;
  3. public class EnemyTank extends Tank implements Runnable {
  4. //在敌人坦克类使用Vector保存多个shot
  5. Vector<Shot> shots = new Vector<>();
  6. boolean isLive = true;
  7. //增加一个成员,EnemyTank 可以得到敌人坦克成员的Vector,用于循环比较是否重叠
  8. Vector<EnemyTank> enemyTanks = new Vector<>();
  9. public EnemyTank(int x, int y) {
  10. super(x, y);
  11. }
  12. //这里提供一个方法,可以将MyPanel的成员 Vector<EnemyTank> enemyTanks = new Vector<>();
  13. // 设置到Enemy 的成员enemyTank
  14. public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
  15. this.enemyTanks = enemyTanks;
  16. }
  17. /**
  18. * 编写方法,判断当前敌人坦克是否和enemyTanks中的其他坦克发生了重叠或碰撞
  19. * 思路:读取一个坦克的坐标,在前进之前先将该坦克坐标与当前所有坦克的坐标依次比较,
  20. * 如果到达某个坦克的边缘则不能再前进,则更改方向前进
  21. */
  22. public boolean isTouchEnemyTank() {
  23. //判断当前敌人坦克(this)方向
  24. switch (this.getDirect()) {
  25. case 0://向上
  26. //让当前的this敌人坦克和其他所有的敌人坦克比较
  27. for (int i = 0; i < enemyTanks.size(); i++) {
  28. //Vector 中取出一个敌人坦克
  29. EnemyTank enemyTank = enemyTanks.get(i);
  30. //不和自己比较
  31. if (enemyTank != this) {
  32. //如果敌人坦克是上/下方向
  33. /**
  34. * 情况1.this坦克向上,如果敌人的坦克是上/下方向
  35. * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+40]
  36. * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+60]
  37. * */
  38. if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
  39. //this坦克的左上角的坐标(this.getX(),this.getY())
  40. if (this.getX() >= enemyTank.getX()
  41. && this.getX() <= enemyTank.getX() + 40
  42. && this.getY() >= enemyTank.getY()
  43. && this.getY() <= enemyTank.getY() + 60) {
  44. return true;//如果进入左上角了该范围,说明发生了碰撞,返回true
  45. }
  46. //this坦克的右上角的坐标(this.getX()+40,this.getY())
  47. if (this.getX() + 40 >= enemyTank.getX()
  48. && this.getX() + 40 <= enemyTank.getX() + 40
  49. && this.getY() >= enemyTank.getY()
  50. && this.getY() <= enemyTank.getY() + 60) {
  51. return true;//如果右上角进入了该范围,说明发生了碰撞,返回true
  52. }
  53. }
  54. //如果敌人坦克是右/左方向
  55. /**
  56. * 情况2.this坦克向上,如果敌人的坦克是右/左方向
  57. * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+60]
  58. * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+40]
  59. * */
  60. if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
  61. //this坦克的左上角的坐标(this.getX(),this.getY())
  62. if (this.getX() >= enemyTank.getX()
  63. && this.getX() <= enemyTank.getX() + 60
  64. && this.getY() >= enemyTank.getY()
  65. && this.getY() <= enemyTank.getY() + 40) {
  66. return true;//如果进入左上角了该范围,说明发生了碰撞,返回true
  67. }
  68. //this坦克的右上角的坐标(this.getX()+40,this.getY())
  69. if (this.getX() + 40 >= enemyTank.getX()
  70. && this.getX() + 40 <= enemyTank.getX() + 60
  71. && this.getY() >= enemyTank.getY()
  72. && this.getY() <= enemyTank.getY() + 40) {
  73. return true;//如果右上角进入了该范围,说明发生了碰撞,返回true
  74. }
  75. }
  76. }
  77. }
  78. break;
  79. case 1://向右
  80. //让当前的this敌人坦克和其他所有的敌人坦克比较
  81. for (int i = 0; i < enemyTanks.size(); i++) {
  82. //Vector 中取出一个敌人坦克
  83. EnemyTank enemyTank = enemyTanks.get(i);
  84. //不和自己比较
  85. if (enemyTank != this) {
  86. //如果敌人坦克是上/下方向
  87. /**
  88. * 情况3.this坦克向右,如果敌人的坦克是上/下方向
  89. * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+40]
  90. * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+60]
  91. * */
  92. if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
  93. //this坦克的右上角的坐标(this.getX()+60,this.getY())
  94. if (this.getX() + 60 >= enemyTank.getX()
  95. && this.getX() + 60 <= enemyTank.getX() + 40
  96. && this.getY() >= enemyTank.getY()
  97. && this.getY() <= enemyTank.getY() + 60) {
  98. return true;//如果进入右上角了该范围,说明发生了碰撞,返回true
  99. }
  100. //this坦克的右下角的坐标(this.getX()+60,this.getY()+40)
  101. if (this.getX() + 60 >= enemyTank.getX()
  102. && this.getX() + 60 <= enemyTank.getX() + 40
  103. && this.getY() + 40 >= enemyTank.getY()
  104. && this.getY() + 40 <= enemyTank.getY() + 60) {
  105. return true;//如果右下角进入了该范围,说明发生了碰撞,返回true
  106. }
  107. }
  108. //如果敌人坦克是右/左方向
  109. /**
  110. * 情况4.this坦克向右,如果敌人的坦克是右/左方向
  111. * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+60]
  112. * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+40]
  113. * */
  114. if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
  115. //this坦克的右上角的坐标(this.getX()+60,this.getY())
  116. if (this.getX() + 60 >= enemyTank.getX()
  117. && this.getX() + 60 <= enemyTank.getX() + 60
  118. && this.getY() >= enemyTank.getY()
  119. && this.getY() <= enemyTank.getY() + 40) {
  120. return true;//如果进入右上角了该范围,说明发生了碰撞,返回true
  121. }
  122. //this坦克的右下角的坐标(this.getX()+60,this.getY()+40)
  123. if (this.getX() + 60 >= enemyTank.getX()
  124. && this.getX() + 60 <= enemyTank.getX() + 60
  125. && this.getY() + 40 >= enemyTank.getY()
  126. && this.getY() + 40 <= enemyTank.getY() + 40) {
  127. return true;//如果右下角进入了该范围,说明发生了碰撞,返回true
  128. }
  129. }
  130. }
  131. }
  132. break;
  133. case 2://向下
  134. for (int i = 0; i < enemyTanks.size(); i++) {
  135. //Vector 中取出一个敌人坦克
  136. EnemyTank enemyTank = enemyTanks.get(i);
  137. //不和自己比较
  138. if (enemyTank != this) {
  139. //如果敌人坦克是上/下方向
  140. /**
  141. * 情况5.this坦克向下,如果敌人的坦克是上/下方向
  142. * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+40]
  143. * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+60]
  144. * */
  145. if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
  146. //this坦克的左下角的坐标(this.getX(),this.getY()+60)
  147. if (this.getX() >= enemyTank.getX()
  148. && this.getX() <= enemyTank.getX() + 40
  149. && this.getY() + 60 >= enemyTank.getY()
  150. && this.getY() + 60 <= enemyTank.getY() + 60) {
  151. return true;//如果进入左下角了该范围,说明发生了碰撞,返回true
  152. }
  153. //this坦克的右下角的坐标(this.getX()+40,this.getY()+60)
  154. if (this.getX() + 40 >= enemyTank.getX()
  155. && this.getX() + 40 <= enemyTank.getX() + 40
  156. && this.getY() + 60 >= enemyTank.getY()
  157. && this.getY() + 60 <= enemyTank.getY() + 60) {
  158. return true;//如果右下角进入了该范围,说明发生了碰撞,返回true
  159. }
  160. }
  161. //如果敌人坦克是右/左方向
  162. /**
  163. * 情况6.this坦克向下,如果敌人的坦克是右/左方向
  164. * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+60]
  165. * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+40]
  166. * */
  167. if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
  168. //this坦克的左下角的坐标(this.getX(),this.getY()+60)
  169. if (this.getX() >= enemyTank.getX()
  170. && this.getX() <= enemyTank.getX() + 60
  171. && this.getY() + 60 >= enemyTank.getY()
  172. && this.getY() + 60 <= enemyTank.getY() + 40) {
  173. return true;//如果进入左下角了该范围,说明发生了碰撞,返回true
  174. }
  175. //this坦克的右下角的坐标(this.getX()+40,this.getY()+60)
  176. if (this.getX() + 40 >= enemyTank.getX()
  177. && this.getX() + 40 <= enemyTank.getX() + 60
  178. && this.getY() + 60 >= enemyTank.getY()
  179. && this.getY() + 60 <= enemyTank.getY() + 40) {
  180. return true;//如果右下角进入了该范围,说明发生了碰撞,返回true
  181. }
  182. }
  183. }
  184. }
  185. break;
  186. case 3://向左
  187. for (int i = 0; i < enemyTanks.size(); i++) {
  188. //Vector 中取出一个敌人坦克
  189. EnemyTank enemyTank = enemyTanks.get(i);
  190. //不和自己比较
  191. if (enemyTank != this) {
  192. //如果敌人坦克是上/下方向
  193. /**
  194. * 情况7.this坦克向左,如果敌人的坦克是上/下方向
  195. * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+40]
  196. * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+60]
  197. * */
  198. if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
  199. //this坦克的左上角的坐标(this.getX(),this.getY())
  200. if (this.getX() >= enemyTank.getX()
  201. && this.getX() <= enemyTank.getX() + 40
  202. && this.getY() >= enemyTank.getY()
  203. && this.getY() <= enemyTank.getY() + 60) {
  204. return true;//如果进入左上角了该范围,说明发生了碰撞,返回true
  205. }
  206. //this坦克的左下角的坐标(this.getX(),this.getY()+40)
  207. if (this.getX() >= enemyTank.getX()
  208. && this.getX() <= enemyTank.getX() + 40
  209. && this.getY() + 40 >= enemyTank.getY()
  210. && this.getY() + 40 <= enemyTank.getY() + 60) {
  211. return true;//如果左下角进入了该范围,说明发生了碰撞,返回true
  212. }
  213. }
  214. //如果敌人坦克是右/左方向
  215. /**
  216. * 情况8.this坦克向左,如果敌人的坦克是右/左方向
  217. * 那么敌人坦克x的范围是[enemyTank.getX(),enemyTank.getX()+60]
  218. * 敌人坦克y的范围是[enemyTank.getY(),enemyTank.getY()+40]
  219. * */
  220. if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
  221. //this坦克的左上角的坐标(this.getX(),this.getY())
  222. if (this.getX() >= enemyTank.getX()
  223. && this.getX() <= enemyTank.getX() + 60
  224. && this.getY() >= enemyTank.getY()
  225. && this.getY() <= enemyTank.getY() + 40) {
  226. return true;//如果进入左下角了该范围,说明发生了碰撞,返回true
  227. }
  228. //this坦克的左下角的坐标(this.getX(),this.getY()+40)
  229. if (this.getX() >= enemyTank.getX()
  230. && this.getX() <= enemyTank.getX() + 60
  231. && this.getY() + 40 >= enemyTank.getY()
  232. && this.getY() + 40 <= enemyTank.getY() + 40) {
  233. return true;//如果右下角进入了该范围,说明发生了碰撞,返回true
  234. }
  235. }
  236. }
  237. }
  238. break;
  239. }
  240. return false;
  241. }
  242. @Override
  243. public void run() {
  244. while (true) {
  245. //这我们先判断当前的坦克是否存活
  246. // 在判断shots.size<3是否真,为真,说明当前的3颗子弹已经消亡了,
  247. // 就创建一颗子弹,放到shots集合中,并启动线程
  248. if (isLive && (shots.size() < 3)) {//可以通过控制数字来修改敌人坦克一次发射几颗子弹
  249. Shot s = null;
  250. //判断坦克的方创建对应的子弹
  251. switch (getDirect()) {
  252. case 0://向上
  253. s = new Shot(getX() + 20, getY(), 0);
  254. break;
  255. case 1://向右
  256. s = new Shot(getX() + 60, getY() + 20, 1);
  257. break;
  258. case 2://向下
  259. s = new Shot(getX() + 20, getY() + 60, 2);
  260. break;
  261. case 3://向左
  262. s = new Shot(getX(), getY() + 20, 3);
  263. break;
  264. }
  265. shots.add(s);
  266. new Thread(s).start();
  267. }
  268. //根据坦克的方法来继续移动
  269. switch (getDirect()) {
  270. case 0://上
  271. //让坦克保持一个方向走50步
  272. for (int i = 0; i < 50; i++) {
  273. if (getY() > 0 && !isTouchEnemyTank()) {
  274. moveUp();
  275. }
  276. try {
  277. Thread.sleep(50);
  278. } catch (InterruptedException e) {
  279. e.printStackTrace();
  280. }
  281. }
  282. break;
  283. case 1://右
  284. //让坦克保持一个方向走50步
  285. for (int i = 0; i < 50; i++) {
  286. if (getX() + 60 < 700 && !isTouchEnemyTank()) {//700为面板宽度
  287. moveRight();//走一步
  288. }
  289. try {
  290. Thread.sleep(50);//每走一步就休眠50毫秒
  291. } catch (InterruptedException e) {
  292. e.printStackTrace();
  293. }
  294. }
  295. break;
  296. case 2://下
  297. for (int i = 0; i < 50; i++) {
  298. if (getY() + 60 < 550 && !isTouchEnemyTank()) {//550为面板宽度
  299. moveDown();
  300. }
  301. try {
  302. Thread.sleep(50);
  303. } catch (InterruptedException e) {
  304. e.printStackTrace();
  305. }
  306. }
  307. break;
  308. case 3://左
  309. for (int i = 0; i < 50; i++) {
  310. if (getX() > 0 && !isTouchEnemyTank()) {
  311. moveLeft();
  312. }
  313. try {
  314. Thread.sleep(50);
  315. } catch (InterruptedException e) {
  316. e.printStackTrace();
  317. }
  318. }
  319. break;
  320. }
  321. //随机地改变坦克的方向 0-3
  322. setDirect((int) (Math.random() * 4));//[0,4)的取整
  323. //如果被击中了,就退出线程
  324. if (!isLive) {
  325. break;//退出线程
  326. }
  327. }
  328. }
  329. }
8.1.2.2修改处2

在MyPanel类中的MyPanel()方法,初始化敌人坦克时,将enemyTanks集合设置给 enemyTank

  1. //将enemyTanks集合设置给 enemyTank
  2. enemyTank.setEnemyTanks(enemyTanks);

可以看到,两个坦克移动到相邻的时候不再发生碰撞/重叠:

8.2记录玩家的成绩,存盘退出

8.2.1思路

创建Recorder类,记录我方击毁敌方坦克的数量。

8.2.2代码实现

8.2.2.1修改处1

在MyPanel类中的paint方法前增加一个方法,用来显示信息

  1. /**
  2. * 编写方法,显示我方击毁敌方坦克的信息
  3. */
  4. public void showInfo(Graphics g) {
  5. //画出 玩家的总成绩
  6. g.setColor(Color.BLACK);//设置画笔颜色
  7. Font font = new Font("宋体", Font.BOLD, 20);
  8. g.setFont(font);
  9. g.drawString("您累计击毁敌方坦克", 730, 30);//画出“您累计击毁敌方坦克”的字样
  10. drawTank(760, 55, g, 0, 0);//画一个敌方坦克图案
  11. g.setColor(Color.BLACK);//重新设置画笔颜色
  12. g.drawString(Recorder.getAllEnemyTankNum()+"", 850, 95);
  13. }
8.2.2.2修改处2

在paint方法中调用showInfo方法:

8.2.2.3修改处3

新增Recorder类:

  1. package li.TankGame.version06;
  2. import java.io.BufferedWriter;
  3. import java.io.FileWriter;
  4. import java.io.IOException;
  5. /**
  6. * @author 李
  7. * @version 6.0
  8. * 该类用于记录相关信息,和文件交互
  9. */
  10. public class Recorder {
  11. //定义变量,记录我方击毁敌人坦克数
  12. private static int allEnemyTankNum = 0;
  13. //定义IO对象,用于写入到文件中
  14. private static BufferedWriter bw = null;//处理流
  15. private static String recordFile = "d:\\myRecord.txt";//记录文件的路径
  16. public static int getAllEnemyTankNum() {
  17. return allEnemyTankNum;
  18. }
  19. public static void setAllEnemyTankNum(int allEnemyTankNum) {
  20. Recorder.allEnemyTankNum = allEnemyTankNum;
  21. }
  22. //当我方击毁一辆敌人坦克时,就应该allEnemyTankNum++
  23. public static void addAllEnemyTankNum() {
  24. Recorder.allEnemyTankNum++;
  25. }
  26. //增加一个方法,当游戏退出时,将allEnemyTankNum保存到myRecord.txt文件中
  27. public static void keepRecord() {
  28. try {
  29. bw = new BufferedWriter(new FileWriter(recordFile));
  30. bw.write(allEnemyTankNum + "\n");
  31. } catch (IOException e) {
  32. e.printStackTrace();
  33. } finally {
  34. try {
  35. if (bw != null) {
  36. bw.close();
  37. }
  38. } catch (IOException e) {
  39. e.printStackTrace();
  40. }
  41. }
  42. }
  43. }
8.2.2.4修改处4

在TankGame06类中的构造器TankGame06方法中,增加相应关闭窗口的处理(在关闭窗口时进行数据存储)

  1. public TankGame06(){
  2. mp = new MyPanel();
  3. //将mp放入到Thread,并启动
  4. Thread thread = new Thread(mp);
  5. thread.start();
  6. this.add(mp);//把面板(就是游戏的绘图区域)添加进来
  7. this.setSize(950,600);//设置大小
  8. this.addKeyListener(mp);//让JFrame监听mp的键盘事件
  9. this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//点击窗口的叉时停止运行
  10. this.setVisible(true);//设置显示
  11. //在JFrame中增加相应关闭窗口的处理
  12. this.addWindowListener(new WindowAdapter() {
  13. @Override
  14. public void windowClosing(WindowEvent e) {
  15. Recorder.keepRecord();
  16. System.exit(0);
  17. }
  18. });
  19. }


PS:这里在MyPanel类中的hitTank方法中,发现之前子弹击中敌坦克的判断条件有误,产生了坦克向左边打其他坦克会瞬间爆炸的bug

修正250行、268行后:

day06-IO流应用01的更多相关文章

  1. Java基础知识强化之IO流笔记01:异常的概述和分类

     IO流操作的时候会出现很多问题,java中叫作异常,所以我们先介绍一下异常: 1. 程序的异常:Throwable(Throwable类是java中所有异常或错误的超类) (1)严重问题:Error ...

  2. java——IO流01

    移动文件有一种简单方法,不需要复制文件再删除文件. package com.unir.test01; import java.io.File; import java.io.IOException; ...

  3. IO流(字节流复制)01

    package ioDemo; import java.io.*; /** * IO流(字节流复制) * Created by lcj on 2017/11/2. */ public class bu ...

  4. 01 语言基础+高级:1-8 File类与IO流_day10【缓冲流、转换流、序列化流】

    day10[缓冲流.转换流.序列化流] 主要内容 缓冲流 转换流 序列化流 打印流 教学目标 能够使用字节缓冲流读取数据到程序 能够使用字节缓冲流写出数据到文件 能够明确字符缓冲流的作用和基本用法 能 ...

  5. 01 语言基础+高级:1-8 File类与IO流_day09【字节流、字符流】

    day09[字节流.字符流] 主要内容 IO流 字节流 字符流 异常处理 Properties 教学目标 能够说出IO流的分类和功能 能够使用字节输出流写出数据到文件 能够使用字节输入流读取数据到程序 ...

  6. java IO流详解

    流的概念和作用 学习Java IO,不得不提到的就是JavaIO流. 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  7. IO流01--毕向东JAVA基础教程视频学习笔记

    提要 01 IO流(BufferedWriter)02 IO流(BufferedReader)03 IO流(通过缓冲区复制文本文件)04 IO流(readLine的原理)05 IO流(MyBuffer ...

  8. Java IO流详尽解析

    流的概念和作用 学习Java IO,不得不提到的就是JavaIO流. 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  9. 【转载】JAVA IO 流的总结

    来自http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html,写的很详细 Java流操作有关的类或接口: Java流类图结构: 流的概念和 ...

  10. JavaSE_ IO流 总目录(19~22)

    JavaSE学习总结第19天_IO流119.01 集合的特点和数据结构总结19.02 如何选择使用哪种集合19.03 集合常见功能和遍历方式总结19.04 异常的概述和分类19.05 JVM默认处理异 ...

随机推荐

  1. JQ模糊查询插件

    //构造函数写法 ;(function($,window,document,undefined){//注意这里的分号必须加 //插件的全部代码 var FazzSearch = function (e ...

  2. 在K8S中,节点故障驱逐pod过程时间怎么定义?

    在Kubernetes中,节点故障驱逐Pod的过程涉及多个参数和组件的相互作用.以下是该过程的简要概述: 默认设置:在默认配置下,节点故障时,工作负载的调度周期约为6分钟. 关键参数: node-mo ...

  3. 图像列表组件(TImageList)

    TImageList 组件是一组同样尺寸的图像列表,每一个图像由它的Index值查询. 1.TImageList组件的典型用法 图形列表用于建立和管理大量的图像,主要是配合菜单或者工具栏按钮的使用.图 ...

  4. 【MFC学习一】BROWSEINFO选择路径导出文件

    mfc中使用 BROWSEINFO,使用 bi.lpfn = BrowseCallbackProc; 回调指定默认当前程序所在目录,导出csv文件,注意处理文件内容中的逗号.单引号.数字字符串开头有0 ...

  5. Linux-grep或和与操作

    一.或(or)操作1.使用选项 -Egrep -E 'a1|a2'filename // 找出文件(filename)中包含a1或者包含a2的行 2.使用egrepegrep 'a1|a2' file ...

  6. CentOS7.6离线升级docker20

    本周研发反馈系统升级失败,是因为docker版本太低,需要升级docker20.由于安装系统的服务器没有联网,所以无法在线升级.所以我找了一台联网的CentOS7.6的服务器,下载了docker20和 ...

  7. CF1433E Two Round Dances 题解

    题目传送门 前置知识 圆排列 解法 \(\dfrac{Q_{n}^{\frac{n}{2}}Q_{\frac{n}{2}}^{\frac{n}{2}}}{A_{2}^{2}}\) 即为所求. 同时因为 ...

  8. 遍历用for还是foreach?

    遍历用for还是foreach?这篇文章帮你轻松选择! 在编程的世界里,我们经常需要对数据进行循环处理,常用的两种方法就是:for循环和foreach循环.想象你站在一条装满宝贝的传送带前,你要亲手检 ...

  9. nginx配置反向代理缓存

    说明 最近运维一个网站里面含有不经常变化的小图片,而每次请求都需要调用file接口获取不太合适.所以就想利用nginx的反向代理缓存来减轻服务接口的请求压力. 工作原理 Nginx反向代理缓存,当客户 ...

  10. Java I/O 教程(三) FileOutputStream类

    Java FileOutputStream 用于将字节数据写入文件. 如果你需要将原始数据写入文件,就使用FileOutputStream类. Java.io.FileOutputStream cla ...